kiss 1.0.1 → 1.0.3

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/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