kiss 1.0.1 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.3
@@ -10,7 +10,6 @@ require 'rubygems'
10
10
  require 'yaml'
11
11
  require 'rack'
12
12
  require 'rack/request'
13
- require 'sequel'
14
13
  require 'erubis'
15
14
 
16
15
  require 'kiss/hacks'
@@ -19,7 +18,7 @@ require 'kiss/controller_accessors'
19
18
  require 'kiss/template_methods'
20
19
  require 'kiss/action'
21
20
 
22
- require 'kiss/model'
21
+ autoload :Sequel, 'sequel'
23
22
 
24
23
  module Rack
25
24
  autoload :Bench, 'kiss/rack/bench'
@@ -86,11 +85,11 @@ class Kiss
86
85
 
87
86
  # attributes below are application-wide
88
87
  cattr_reader :action_dir, :template_dir, :email_template_dir, :model_dir, :upload_dir,
89
- :evolution_dir, :asset_dir, :public_dir, :db, :environment, :options, :layout, :rack_file
88
+ :evolution_dir, :asset_dir, :public_dir, :environment, :options, :layout, :rack_file
90
89
 
91
90
  # attributes below are request-specific
92
91
  attr_reader :params, :args, :action, :action_subdir, :action_path, :extension, :host, :request,
93
- :session, :login
92
+ :exception_cache
94
93
 
95
94
  attr_accessor :last_sql
96
95
 
@@ -119,9 +118,6 @@ class Kiss
119
118
  else
120
119
  load(options)
121
120
  end
122
-
123
- # TODO: rewrite evolution file exists check for speed
124
- check_evolution_number if @@db
125
121
 
126
122
  app = self
127
123
  builder_options = @@options[:rack_builder] || []
@@ -199,6 +195,7 @@ class Kiss
199
195
  @@lib_dirs = ['lib']
200
196
  @@gem_dirs = ['gems']
201
197
  @@require = []
198
+ @@authenticate_exclude = ['/logout']
202
199
 
203
200
  # common (shared) config
204
201
  if (File.file?(config_file = @@config_dir+'/common.yml'))
@@ -218,7 +215,6 @@ class Kiss
218
215
  @@asset_dir = @@public_dir = @@options[:asset_dir] || @@options[:public_dir] || 'public_html'
219
216
 
220
217
  @@model_dir = @@options[:model_dir] || 'models'
221
- Kiss::ModelCache.model_dir = @@model_dir
222
218
 
223
219
  @@evolution_dir = @@options[:evolution_dir] || 'evolutions'
224
220
 
@@ -266,32 +262,8 @@ class Kiss
266
262
  end
267
263
 
268
264
  # database
269
- if sequel = @@options[:database]
270
- # open database connection (if not already open)
271
- @@db = sequel.is_a?(String) ? (Sequel.open sequel) : sequel.is_a?(Hash) ? (Sequel.open sequel) : sequel
272
-
273
- if @@db.class.name == 'Sequel::MySQL::Database'
274
- # add fetch_arrays, all_arrays methods
275
- require 'kiss/sequel_mysql'
276
- # turn off convert_tinyint_to_bool, unless options say otherwise
277
- Sequel.convert_tinyint_to_bool = false unless @@options[:convert_tinyint_to_bool]
278
- end
279
- end
280
-
281
- # setup session storage, if session class specified in config
282
- @@session_class.setup_storage(self) if @@session_class
283
-
284
- # prepare authenticate_exclude
285
- if @@options[:authenticate_all]
286
- if @@options[:authenticate_exclude].is_a?(Array)
287
- @@options[:authenticate_exclude] = @@options[:authenticate_exclude].map do |action|
288
- action = '/'+action unless action =~ /\A\//
289
- action
290
- end
291
- else
292
- @@options[:authenticate_exclude] = []
293
- end
294
- end
265
+ @@database_config = @@options[:database]
266
+ @@database_pool = []
295
267
 
296
268
  self
297
269
  end
@@ -328,6 +300,9 @@ class Kiss
328
300
  if require_libs = config_options.delete(:require)
329
301
  @@require.push( require_libs )
330
302
  end
303
+ if auth_exclude = config_options.delete(:authenticate_exclude)
304
+ @@authenticate_exclude.push( *(auth_exclude.map { |action| action =~ /\A\// ? action : '/'+action }) )
305
+ end
331
306
 
332
307
  @@options.merge!( config_options )
333
308
  end
@@ -413,11 +388,6 @@ class Kiss
413
388
 
414
389
  text
415
390
  end
416
-
417
- # Returns exception cache, for use in Kiss::ExceptionReport.
418
- def exception_cache
419
- @@exception_cache
420
- end
421
391
 
422
392
  # Given a file path, caches or returns the file's contents or the return value of
423
393
  # the passed block applied to the file's contents.
@@ -449,39 +419,6 @@ class Kiss
449
419
  (block_given?) ? yield(contents) : contents
450
420
  end
451
421
  end
452
-
453
- # Returns Sequel dataset to evolution_number table, which specifies app's current evolution number.
454
- # Creates evolution_number table if it does not exist.
455
- def evolution_number_table
456
- unless db.table_exists?(:evolution_number)
457
- db.create_table :evolution_number do
458
- column :version, :integer, :null=> false
459
- end
460
- db[:evolution_number].insert(:version => 0)
461
- end
462
- db[:evolution_number]
463
- end
464
-
465
- # Returns app's current evolution number.
466
- def evolution_number
467
- evolution_number_table.first.version
468
- end
469
-
470
- # Sets app's current evolution number.
471
- def evolution_number=(version)
472
- load unless @@options
473
- evolution_number_table.update(:version => version)
474
- end
475
-
476
- # Check whether there exists a file in evolution_dir whose number is greater than app's
477
- # current evolution number. If so, raise an error to indicate need to apply new evolutions.
478
- def check_evolution_number
479
- version = evolution_number
480
- if Kiss.directory_exists?(@@evolution_dir) &&
481
- Dir.entries(@@evolution_dir).select { |f| f =~ /\A0*#{version+1}_/ }.size > 0
482
- raise "current evolution #{version} is outdated; apply evolutions or update evolution number"
483
- end
484
- end
485
422
  end # end class methods
486
423
 
487
424
  ### Instance Methods
@@ -531,16 +468,17 @@ class Kiss
531
468
  env['kiss.parsed_action'] = @action
532
469
  env['kiss.parsed_args'] = @args.inspect
533
470
 
534
- setup_session
471
+ redirect_url(app_url + '/') if @action == '/login'
472
+
535
473
  if login_session_valid?
536
474
  load_from_login_session
537
475
  elsif @@options[:authenticate_all]
538
- if (!@@options[:authenticate_exclude].is_a?(Array) ||
539
- @@options[:authenticate_exclude].select {|action| action == @action}.size == 0)
476
+ if (!@@authenticate_exclude.is_a?(Array) ||
477
+ @@authenticate_exclude.select {|action| action == @action}.size == 0)
540
478
  authenticate
541
479
  end
542
480
  end
543
-
481
+
544
482
  env['kiss.processed_action'] = @action
545
483
  process.render
546
484
  end
@@ -548,7 +486,7 @@ class Kiss
548
486
 
549
487
  @response.finish
550
488
  rescue StandardError, LoadError, SyntaxError => e
551
- body = Kiss::ExceptionReport.generate(e, env, @exception_cache, @last_sql)
489
+ body = Kiss::ExceptionReport.generate(e, env, @exception_cache, @db ? @db.last_query : nil)
552
490
  if @@exception_log_file
553
491
  @@exception_log_file.print(body + "\n--- End of exception report --- \n\n")
554
492
  end
@@ -573,6 +511,8 @@ class Kiss
573
511
  headers['Content-Length'] = body.length.to_s
574
512
  end
575
513
 
514
+ @@database_pool.push(@db) if @db
515
+
576
516
  [code,headers,body]
577
517
  end
578
518
 
@@ -622,27 +562,37 @@ class Kiss
622
562
  suffix ? @app_url + suffix : @app_url
623
563
  end
624
564
 
625
- # Loads session from session store (specified by session_class).
626
- def setup_session
627
- @login = {}
628
- @session = @@session_class ? begin
629
- session = @@session_class.persist(@request.cookies[@@cookie_name])
630
- @session_fingerprint = Marshal.dump(session.data).hash
631
-
632
- cookie_vars = {
633
- :value => session.values[:session_id],
634
- :path => @@options[:cookie_path] || @app_uri,
635
- :domain => @@options[:cookie_domain] || @request.host
636
- }
637
- cookie_vars[:expires] = Time.now + @@options[:cookie_lifespan] if @@options[:cookie_lifespan]
638
-
639
- # set_cookie here or at render time
640
- @response.set_cookie @@cookie_name, cookie_vars
641
- @login.merge!(session[:login]) if session[:login] && session[:login][:expires_at] &&
642
- session[:login][:expires_at] > Time.now
643
-
644
- session
645
- end : {}
565
+ # Returns Sequel dataset to evolution_number table, which specifies app's current evolution number.
566
+ # Creates evolution_number table if it does not exist.
567
+ def evolution_number_table
568
+ unless db.table_exists?(:evolution_number)
569
+ db.create_table :evolution_number do
570
+ column :version, :integer, :null=> false
571
+ end
572
+ db[:evolution_number].insert(:version => 0)
573
+ end
574
+ db[:evolution_number]
575
+ end
576
+
577
+ # Returns app's current evolution number.
578
+ def evolution_number
579
+ evolution_number_table.first.version
580
+ end
581
+
582
+ # Sets app's current evolution number.
583
+ def evolution_number=(version)
584
+ load unless @@options
585
+ evolution_number_table.update(:version => version)
586
+ end
587
+
588
+ # Check whether there exists a file in evolution_dir whose number is greater than app's
589
+ # current evolution number. If so, raise an error to indicate need to apply new evolutions.
590
+ def check_evolution_number
591
+ version = evolution_number
592
+ if Kiss.directory_exists?(@@evolution_dir) &&
593
+ Dir.entries(@@evolution_dir).select { |f| f =~ /\A0*#{version+1}_/ }.size > 0
594
+ raise "current evolution #{version} is outdated; apply evolutions or update evolution number"
595
+ end
646
596
  end
647
597
 
648
598
  # Saves session to session store, if session data has changed since load.
@@ -652,21 +602,62 @@ class Kiss
652
602
 
653
603
  ##### LOGIN SESSION #####
654
604
 
655
- # Empties request and session login hashes.
656
- def reset_login_session
657
- @session[:login] = @login = {}
605
+ def session
606
+ @session ||= begin
607
+ @@session_class ? begin
608
+ @@session_setup ||= begin
609
+ # setup session storage
610
+ @@session_class.setup_storage(self)
611
+ true
612
+ end
613
+
614
+ session = @@session_class.persist(self,@request.cookies[@@cookie_name])
615
+ @session_fingerprint = Marshal.dump(session.data).hash
616
+
617
+ cookie_vars = {
618
+ :value => session.values[:session_id],
619
+ :path => @@options[:cookie_path] || @app_uri,
620
+ :domain => @@options[:cookie_domain] || @request.host
621
+ }
622
+ cookie_vars[:expires] = Time.now + @@options[:cookie_lifespan] if @@options[:cookie_lifespan]
623
+
624
+ # set_cookie here or at render time
625
+ @response.set_cookie @@cookie_name, cookie_vars
626
+
627
+ session
628
+ end : {}
629
+ end
658
630
  end
659
- alias_method :reset_login_data, :reset_login_session
631
+
632
+ def login
633
+ @login ||= begin
634
+ login = {}
635
+
636
+ login.merge!(session[:login]) if (session[:login] && session[:login][:expires_at] &&
637
+ session[:login][:expires_at] > Time.now)
638
+
639
+ login
640
+ end
641
+ end
642
+
643
+ # Deletes login data from session.
644
+ def logout
645
+ session.delete(:login)
646
+ @login = nil
647
+ end
648
+ alias_method :reset_login_session, :logout
649
+ alias_method :reset_login_data, :logout
660
650
 
661
651
  # Merges data hash (key-value pairs) into request login hash.
662
652
  def set_login_data(data)
663
- @login = @login.merge(data)
653
+ login.merge!(data)
654
+ login
664
655
  end
665
656
 
666
657
  # Merges data hash (key-value pairs) into session login hash.
667
658
  def set_login_session(data)
668
659
  set_login_data(data)
669
- @session[:login] = (@session[:login] || {}).merge(data)
660
+ session[:login] = (session[:login] || {}).merge(data)
670
661
  end
671
662
 
672
663
  # Sets expire time of session login hash, after which time it will be reset (emptied).
@@ -678,12 +669,12 @@ class Kiss
678
669
 
679
670
  # Returns true if login hash is defined and not expired.
680
671
  def login_session_valid?
681
- @login && !login_session_expired?
672
+ login && !login_session_expired?
682
673
  end
683
674
 
684
675
  # Returns true if login hash is expired.
685
676
  def login_session_expired?
686
- @login && (!@login[:expires_at] || @login[:expires_at] < Time.now)
677
+ login && (!login[:expires_at] || login[:expires_at] < Time.now)
687
678
  end
688
679
 
689
680
  # Calls login action's load_from_session method to populate request login hash.
@@ -708,10 +699,13 @@ class Kiss
708
699
  else
709
700
  klass = action_class('/login')
710
701
  raise 'authenticate called, but no login action found' unless klass
711
- old_extension = @extension
712
- @extension = 'rhtml'
702
+
703
+ old_template = @template
704
+ @template = '/login.rhtml'
705
+
713
706
  process(klass,login_path)
714
- @extension = old_extension
707
+
708
+ @template = old_template
715
709
 
716
710
  unless login_session_valid?
717
711
  #raise 'login action completed without setting valid login session'
@@ -825,19 +819,69 @@ class Kiss
825
819
  mailer
826
820
  end
827
821
 
822
+ def db
823
+ @db ||= @@database_pool.shift || begin
824
+ raise 'database config missing' unless @@database_config
825
+
826
+ # open database connection (if not already open)
827
+ @db = @@database_config.is_a?(String) ? (Sequel.open @@database_config) :
828
+ @@database_config.is_a?(Hash) ? (Sequel.open @@database_config) : @@database_config
829
+
830
+ @@db_extras_loaded ||= begin
831
+ @db.class.class_eval do
832
+ @last_query = nil
833
+ def last_query
834
+ @last_query
835
+ end
836
+
837
+ alias_method :execute_old, :execute
838
+ def execute(sql, *args, &block)
839
+ @last_query = sql
840
+ execute_old(sql, *args, &block)
841
+ end
842
+ end
843
+
844
+ require 'kiss/model'
845
+ Kiss::ModelCache.model_dir = @@model_dir
846
+
847
+ if @db.class.name == 'Sequel::MySQL::Database'
848
+ # add fetch_arrays, all_arrays methods
849
+ require 'kiss/sequel_mysql'
850
+ # turn off convert_tinyint_to_bool, unless options say otherwise
851
+ Sequel.convert_tinyint_to_bool = false unless @@options[:convert_tinyint_to_bool]
852
+ end
853
+ true
854
+ end
855
+
856
+ # TODO: rewrite evolution file exists check for speed
857
+ check_evolution_number
858
+
859
+ @db
860
+ end
861
+ end
862
+
828
863
  # Kiss Model cache, used to invoke and store Kiss database models.
829
864
  #
830
865
  # Example:
831
866
  # models[:users] : database model for `users' table
832
867
  def dbm
868
+ db unless @db
833
869
  @dbm ||= Kiss::ModelCache.new(self)
834
870
  end
835
871
  alias_method :models, :dbm
836
872
 
873
+ def random_text(*args)
874
+ self.class.random_text(*args)
875
+ end
876
+
837
877
  def h(*args)
838
878
  self.class.h(*args)
839
879
  end
840
880
 
881
+ def template
882
+ @template || @action
883
+ end
884
+
841
885
  # Adds data to be displayed in "Cache" section of Kiss exception reports.
842
886
  def set_exception_cache(data)
843
887
  @exception_cache.merge!(data)
@@ -114,9 +114,9 @@ class Kiss
114
114
  @base_url ||= app(action_subdir + '/')
115
115
  @layout = options.is_a?(Hash) && options.has_key?(:layout) ? options[:layout] :
116
116
  (extension == 'rhtml' ? Kiss.layout : nil)
117
-
117
+
118
118
  content = options[:content].is_a?(String) ? options[:content] : process({
119
- :template => action,
119
+ :template => template,
120
120
  :extension => extension
121
121
  }.merge(options))
122
122
 
@@ -3,11 +3,6 @@ class Kiss
3
3
  def environment
4
4
  Kiss.environment
5
5
  end
6
-
7
- def db
8
- Kiss.db
9
- end
10
- alias_method :database, :db
11
6
 
12
7
  def upload_dir
13
8
  Kiss.upload_dir
@@ -27,6 +22,11 @@ class Kiss
27
22
  controller.bench(label, Kernel.caller[0])
28
23
  end
29
24
 
25
+ def db
26
+ controller.db
27
+ end
28
+ alias_method :database, :db
29
+
30
30
  def dbm
31
31
  controller.dbm
32
32
  end
@@ -67,6 +67,10 @@ class Kiss
67
67
  def set_login_session(*args)
68
68
  controller.set_login_session(*args)
69
69
  end
70
+
71
+ def logout
72
+ controller.logout
73
+ end
70
74
 
71
75
  def reset_login_data
72
76
  controller.reset_login_data
@@ -92,6 +96,10 @@ class Kiss
92
96
  controller.action
93
97
  end
94
98
 
99
+ def template
100
+ controller.template
101
+ end
102
+
95
103
  def action_subdir
96
104
  controller.action_subdir
97
105
  end
@@ -90,6 +90,7 @@ class Kiss
90
90
  h2 span { font-size:80%; color:#000; font-weight:normal; }
91
91
  h3 { margin:1em 0 .5em 0; }
92
92
  h4 { margin:0 0 .5em 0; font-weight: normal; }
93
+ small { color #444; }
93
94
  table {
94
95
  border:1px solid #ccc; border-collapse: collapse; background:white; }
95
96
  tbody td, tbody th { vertical-align:top; padding:2px 3px; }
@@ -3,7 +3,7 @@
3
3
 
4
4
  # Placeholder; to be overloaded by Kiss Rack builder option MultiBench
5
5
  # (not yet implemented).
6
- def multibench(*args); end
6
+ # def multibench(*args); end
7
7
 
8
8
  # This gets called outside of controller contexts; used mainly for debugging
9
9
  # during Kiss framework development.
@@ -72,19 +72,6 @@ class Fixnum
72
72
  end
73
73
  end
74
74
 
75
- class BigDecimal
76
- # Formats number with comma-separated thousands.
77
- def format_thousands(value = to_f.to_s)
78
- integer, decimal = value.split(/\./,2)
79
- integer.reverse.gsub(/(\d{3})/,'\1,').sub(/\,(-?)$/,'\1').reverse + '.' + decimal
80
- end
81
-
82
- # Formats number to two decimal places.
83
- def format_currency
84
- format_thousands(sprintf("%0.2f",to_f))
85
- end
86
- end
87
-
88
75
  class Date
89
76
  # Returns string representing date in m/d/yyyy format
90
77
  def mdy
@@ -110,6 +97,44 @@ class NilClass
110
97
  end
111
98
  end
112
99
 
100
+ class String
101
+ def to_const
102
+ begin
103
+ parts = self.split(/::/)
104
+ klass = Kernel
105
+ while (next_part = parts.shift)
106
+ klass = klass.const_get(next_part)
107
+ end
108
+
109
+ klass
110
+ rescue
111
+ raise "Constant '#{self}' not defined"
112
+ end
113
+ end
114
+ end
115
+
116
+ class Symbol
117
+ def to_const
118
+ self.to_s.to_const
119
+ end
120
+ end
121
+
122
+ module Rack
123
+ class Request
124
+ def server
125
+ url = scheme + "://"
126
+ url << host
127
+
128
+ if scheme == "https" && port != 443 ||
129
+ scheme == "http" && port != 80
130
+ url << ":#{port}"
131
+ end
132
+
133
+ url
134
+ end
135
+ end
136
+ end
137
+
113
138
  class SequelZeroTime < String
114
139
  def initialize(value = '0000-00-00 00:00',*args,&block)
115
140
  super(value,*args,&block)
@@ -157,95 +182,3 @@ class SequelZeroTime < String
157
182
  ''
158
183
  end
159
184
  end
160
-
161
- class Date
162
- class << self
163
- alias_method :old_parse, :parse
164
- def parse(*args, &block)
165
- return SequelZeroTime.new(args[0]) if args[0] =~ /0000/
166
- old_parse(*args, &block)
167
- end
168
- end
169
-
170
- # comparision operators
171
- def ==(value)
172
- (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
173
- end
174
- def >(value)
175
- (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
176
- end
177
- def >=(value)
178
- (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
179
- end
180
- def <(value)
181
- (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
182
- end
183
- def <=(value)
184
- (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
185
- end
186
- end
187
-
188
- class Time
189
- class << self
190
- alias_method :old_parse, :parse
191
- def parse(*args, &block)
192
- return SequelZeroTime.new(args[0]) if args[0] =~ /0000/
193
- old_parse(*args, &block)
194
- end
195
- end
196
-
197
- # comparision operators
198
- def ==(value)
199
- (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
200
- end
201
- def >(value)
202
- (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
203
- end
204
- def >=(value)
205
- (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
206
- end
207
- def <(value)
208
- (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
209
- end
210
- def <=(value)
211
- (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
212
- end
213
- end
214
-
215
- class String
216
- def to_const
217
- begin
218
- parts = self.split(/::/)
219
- klass = Kernel
220
- while (next_part = parts.shift)
221
- klass = klass.const_get(next_part)
222
- end
223
-
224
- klass
225
- rescue
226
- raise "Constant '#{self}' not defined"
227
- end
228
- end
229
- end
230
-
231
- class Symbol
232
- def to_const
233
- self.to_s.to_const
234
- end
235
- end
236
-
237
- module Rack
238
- class Request
239
- def server
240
- url = scheme + "://"
241
- url << host
242
-
243
- if scheme == "https" && port != 443 ||
244
- scheme == "http" && port != 80
245
- url << ":#{port}"
246
- end
247
-
248
- url
249
- end
250
- end
251
- end
@@ -76,8 +76,7 @@ class Kiss
76
76
 
77
77
  def [](source)
78
78
  @cache[source] ||= begin
79
- dataset = Model.db[source]
80
- dataset.controller = @controller
79
+ dataset = @controller.db[source]
81
80
  (@@model_dir && source.is_a?(Symbol)) ? begin
82
81
  # use file_cache
83
82
  model_path = "#{@@model_dir}/#{source}.rb"
@@ -101,7 +100,7 @@ class Kiss
101
100
  end
102
101
 
103
102
  def db
104
- Sequel::Model.db
103
+ @controller.db
105
104
  end
106
105
 
107
106
  def literal(*args)
@@ -132,15 +131,69 @@ class Sequel::Model
132
131
  end
133
132
  end
134
133
 
135
- class Sequel::Dataset
136
- def controller=(controller)
137
- @controller = controller
134
+ class Date
135
+ class << self
136
+ alias_method :old_parse, :parse
137
+ def parse(*args, &block)
138
+ return SequelZeroTime.new(args[0]) if args[0] =~ /0000/
139
+ old_parse(*args, &block)
140
+ end
138
141
  end
139
142
 
140
- def execute(sql, opts={}, &block)
141
- if @controller
142
- @controller.last_sql = sql
143
+ # comparision operators
144
+ def ==(value)
145
+ (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
146
+ end
147
+ def >(value)
148
+ (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
149
+ end
150
+ def >=(value)
151
+ (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
152
+ end
153
+ def <(value)
154
+ (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
155
+ end
156
+ def <=(value)
157
+ (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
158
+ end
159
+ end
160
+
161
+ class Time
162
+ class << self
163
+ alias_method :old_parse, :parse
164
+ def parse(*args, &block)
165
+ return SequelZeroTime.new(args[0]) if args[0] =~ /0000/
166
+ old_parse(*args, &block)
143
167
  end
144
- @db.execute(sql, {:server=>@opts[:server] || :read_only}.merge(opts), &block)
168
+ end
169
+
170
+ # comparision operators
171
+ def ==(value)
172
+ (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
173
+ end
174
+ def >(value)
175
+ (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
176
+ end
177
+ def >=(value)
178
+ (value == 0 || value.is_a?(SequelZeroTime)) ? true : super(value)
179
+ end
180
+ def <(value)
181
+ (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
182
+ end
183
+ def <=(value)
184
+ (value == 0 || value.is_a?(SequelZeroTime)) ? false : super(value)
185
+ end
186
+ end
187
+
188
+ class BigDecimal
189
+ # Formats number with comma-separated thousands.
190
+ def format_thousands(value = to_f.to_s)
191
+ integer, decimal = value.split(/\./,2)
192
+ integer.reverse.gsub(/(\d{3})/,'\1,').sub(/\,(-?)$/,'\1').reverse + '.' + decimal
193
+ end
194
+
195
+ # Formats number to two decimal places.
196
+ def format_currency
197
+ format_thousands(sprintf("%0.2f",to_f))
145
198
  end
146
199
  end
@@ -53,8 +53,8 @@ class Kiss
53
53
  end
54
54
 
55
55
  # Generates a new session ID and creates a row for the new session in the database.
56
- def generate
57
- new(Sequel::Model(:sessions).create(
56
+ def generate(controller)
57
+ new(Sequel::Model(controller.db[:sessions]).create(
58
58
  :session_id => rand_uuid,
59
59
  :data => marshal({}),
60
60
  :created_at => Time.now,
@@ -64,14 +64,14 @@ class Kiss
64
64
 
65
65
  # Gets the existing session based on the <tt>session_id</tt> available in cookies.
66
66
  # If none is found, generates a new session.
67
- def persist(session_id)
67
+ def persist(controller, session_id)
68
68
  if session_id
69
- if object = Sequel::Model(:sessions).where(:session_id => session_id).first
69
+ if object = Sequel::Model(controller.db[:sessions]).where(:session_id => session_id).first
70
70
  session = new( object )
71
71
  end
72
72
  end
73
73
  unless session
74
- session = generate
74
+ session = generate( controller.db )
75
75
  end
76
76
  session
77
77
  end
@@ -66,7 +66,15 @@ class Kiss
66
66
  def get_template_path(options)
67
67
  @current_template_dir ||= @template_dir + action_subdir
68
68
 
69
- path = options.is_a?(String) ? options : "#{options[:template]}.#{options[:extension] || 'rhtml'}"
69
+ if options.is_a?(String)
70
+ path = options
71
+ extension = nil
72
+ else
73
+ path = options[:template]
74
+ extension = options[:extension]
75
+ end
76
+
77
+ path += ".#{extension || 'rhtml'}" unless path =~ /\./
70
78
  (path =~ /\A\//) ? "#{@template_dir}#{path}" : "#{@current_template_dir}/#{path}"
71
79
  end
72
80
 
@@ -85,12 +93,12 @@ class Kiss
85
93
  # macros
86
94
  template.gsub!(/\<\%\s*macro\s+(\w+.*?)\s*\%\>/,'<% def \1; _buf = \'\' %>')
87
95
  template.gsub!(/\<\%\s*end\s+macro\s*\%\>/,'<% _buf; end %>')
88
-
96
+
97
+ # generic loop iterator, using 'iterate'
98
+ template.gsub!(/\<\%\s*iterate\s+(\w+)\s+(.*?)\s*\%\>/,"<% \\1 = Kiss::Iterator.new; \\2; \\1.increment %>")
89
99
  # for loop iterator
90
- template.gsub!(/\<\%\s*for\s+(\w+)\s+in\s+(.*?)\s*\%\>/,'<% loop = Kiss::Iterator.new(\2); for \1 in loop.collection; loop.increment %>')
91
- # while loop iterator
92
- template.gsub!(/\<\%\s*while\s+(.*?)\s*\%\>/,'<% loop = Kiss::Iterator.new; while \1; loop.increment %>')
93
-
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 %>")
101
+
94
102
  Erubis::Eruby.new(template).src
95
103
  end
96
104
  result = eval eruby_src, template_binding, path
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kiss
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shawn Van Ittersum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-09-29 00:00:00 -07:00
12
+ date: 2008-10-05 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency