kiss 1.1 → 1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/bin/kiss +151 -34
- data/data/scaffold.tgz +0 -0
- data/lib/kiss.rb +389 -742
- data/lib/kiss/accessors/controller.rb +47 -0
- data/lib/kiss/accessors/request.rb +106 -0
- data/lib/kiss/accessors/template.rb +23 -0
- data/lib/kiss/action.rb +502 -132
- data/lib/kiss/bench.rb +14 -5
- data/lib/kiss/debug.rb +14 -6
- data/lib/kiss/exception_report.rb +22 -299
- data/lib/kiss/ext/core.rb +700 -0
- data/lib/kiss/ext/rack.rb +33 -0
- data/lib/kiss/ext/sequel_database.rb +47 -0
- data/lib/kiss/ext/sequel_mysql_dataset.rb +23 -0
- data/lib/kiss/form.rb +404 -179
- data/lib/kiss/form/field.rb +183 -307
- data/lib/kiss/form/field_types.rb +239 -0
- data/lib/kiss/format.rb +88 -70
- data/lib/kiss/html/exception_report.css +222 -0
- data/lib/kiss/html/exception_report.html +210 -0
- data/lib/kiss/iterator.rb +14 -12
- data/lib/kiss/login.rb +8 -8
- data/lib/kiss/mailer.rb +68 -66
- data/lib/kiss/model.rb +323 -36
- data/lib/kiss/rack/bench.rb +16 -8
- data/lib/kiss/rack/email_errors.rb +25 -15
- data/lib/kiss/rack/errors_ok.rb +2 -2
- data/lib/kiss/rack/facebook.rb +6 -6
- data/lib/kiss/rack/file_not_found.rb +10 -8
- data/lib/kiss/rack/log_exceptions.rb +3 -3
- data/lib/kiss/rack/recorder.rb +2 -2
- data/lib/kiss/rack/show_debug.rb +2 -2
- data/lib/kiss/rack/show_exceptions.rb +2 -2
- data/lib/kiss/request.rb +435 -0
- data/lib/kiss/sequel_session.rb +15 -14
- data/lib/kiss/static_file.rb +20 -13
- data/lib/kiss/template.rb +327 -0
- metadata +60 -25
- data/lib/kiss/controller_accessors.rb +0 -81
- data/lib/kiss/hacks.rb +0 -188
- data/lib/kiss/sequel_mysql.rb +0 -25
- data/lib/kiss/template_methods.rb +0 -167
data/lib/kiss/login.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
class Kiss
|
2
2
|
class Login < Hash
|
3
3
|
def initialize(session)
|
4
|
-
@
|
5
|
-
@
|
4
|
+
@_session = session
|
5
|
+
@_session['login'] ||= {}
|
6
6
|
|
7
7
|
# check if login expired
|
8
8
|
if expired?
|
9
9
|
# login expired
|
10
|
-
@
|
10
|
+
@_session['login'] = {}
|
11
11
|
end
|
12
12
|
|
13
|
-
@
|
14
|
-
self.merge!(@
|
13
|
+
@_persist_data = @_session['login']
|
14
|
+
self.merge!(@_persist_data)
|
15
15
|
end
|
16
16
|
|
17
17
|
def expired?
|
18
|
-
@
|
18
|
+
@_session['login']['expires_at'] && session['login']['expires_at'] < Time.now
|
19
19
|
end
|
20
20
|
|
21
21
|
def persist(data = {})
|
22
|
-
@
|
22
|
+
@_persist_data.merge!(data)
|
23
23
|
self.merge!(data)
|
24
24
|
end
|
25
25
|
|
@@ -38,7 +38,7 @@ class Kiss
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def clear
|
41
|
-
@
|
41
|
+
@_session['login'] = {}
|
42
42
|
super()
|
43
43
|
end
|
44
44
|
end
|
data/lib/kiss/mailer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Kiss
|
2
2
|
# This class creates, renders, and sends email messages.
|
3
3
|
|
4
|
-
# @
|
4
|
+
# @_options
|
5
5
|
# :server, :port, :domain, :account, :password, :auth - for SMTP login
|
6
6
|
# :from/to - used by SMTP to send message (ignored by sendmail)
|
7
7
|
# :message - message headers/body text
|
@@ -10,91 +10,93 @@ class Kiss
|
|
10
10
|
# :sendmail_path - filesystem path to sendmail executable
|
11
11
|
|
12
12
|
class Mailer
|
13
|
-
|
13
|
+
@@sendmail_path = "/usr/sbin/sendmail -t"
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def send(options)
|
17
|
+
if options[:sendmail] || (options[:engine] == :sendmail) || !options[:server]
|
18
|
+
send_via_sendmail(options)
|
19
|
+
else
|
20
|
+
send_via_smtp(options)
|
21
|
+
end
|
22
|
+
end
|
14
23
|
|
15
|
-
|
24
|
+
# Attempts to send message using /usr/sbin/sendmail.
|
25
|
+
# NOTE: sendmail ignores :from and :to options, using
|
26
|
+
# From and To headers from the message
|
27
|
+
def send_via_sendmail(options)
|
28
|
+
puts options[:message]
|
29
|
+
IO.popen(options[:sendmail] || @@sendmail_path, "w") do |pipe|
|
30
|
+
pipe.puts(options[:message])
|
31
|
+
end
|
32
|
+
end
|
16
33
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
34
|
+
# Attempts to send message using Net::SMTP.
|
35
|
+
def send_via_smtp(options)
|
36
|
+
require 'net/smtp' unless defined?(Net::SMTP)
|
37
|
+
|
38
|
+
Net::SMTP.start(
|
39
|
+
options[:server] || 'localhost',
|
40
|
+
options[:port] || 25,
|
41
|
+
options[:domain] || nil,
|
42
|
+
options[:account] || options[:username] || nil,
|
43
|
+
options[:password] || nil,
|
44
|
+
options[:auth] || :plain
|
45
|
+
) do |smtp|
|
46
|
+
smtp.sendmail(options[:message], options[:from], options[:to])
|
47
|
+
end
|
48
|
+
end
|
21
49
|
end
|
22
50
|
|
51
|
+
include Kiss::ControllerAccessors
|
52
|
+
include Kiss::RequestAccessors
|
53
|
+
include Kiss::DatabaseAccessors
|
54
|
+
include Kiss::TemplateMethods
|
55
|
+
|
56
|
+
_attr_accessor :controller, :request, :options
|
57
|
+
|
23
58
|
# Creates new email message object.
|
24
|
-
def initialize(
|
25
|
-
@
|
26
|
-
|
59
|
+
def initialize(new_options = {})
|
60
|
+
@_options = {}
|
61
|
+
merge_options(new_options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def merge_options(new_options = {})
|
65
|
+
if new_options[:controller]
|
66
|
+
@_controller = new_options[:controller]
|
67
|
+
@_options = @_controller.mailer_config.merge(@_options)
|
68
|
+
end
|
27
69
|
|
28
|
-
|
70
|
+
@_options.merge!(new_options)
|
71
|
+
@_request = new_options[:request] || @_request
|
29
72
|
end
|
30
73
|
|
31
74
|
# Renders email template to string, unless message option is
|
32
75
|
# already set to a string value.
|
33
|
-
def prepare_email_message(
|
34
|
-
merge_options(
|
76
|
+
def prepare_email_message(new_options = {})
|
77
|
+
merge_options(new_options)
|
35
78
|
|
36
|
-
unless @
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
data = vars = @options[:data] || @options[:vars]
|
42
|
-
|
43
|
-
path = "#{@template_dir}/#{template_name}"
|
44
|
-
@options[:message] = erubis(path,binding)
|
79
|
+
unless @_options[:message].is_a?(String)
|
80
|
+
if template = @_options[:template]
|
81
|
+
@@template_class ||= Kiss::Template.get_root_class(controller, controller.email_template_dir)
|
82
|
+
@data = @_options[:data] || @_options[:vars]
|
83
|
+
@_options[:message] = @@template_class.get_subclass_from_path('/'+template).new(request, self).call
|
45
84
|
else
|
46
|
-
raise 'email message
|
85
|
+
raise 'no email message or template found to prepare'
|
47
86
|
end
|
48
87
|
end
|
49
88
|
|
50
|
-
return @
|
89
|
+
return @_options[:message]
|
51
90
|
end
|
52
91
|
|
53
92
|
# Attempts to send message using SMTP, unless :engine option is set to
|
54
93
|
# :sendmail.
|
55
|
-
def send(
|
56
|
-
merge_options(
|
57
|
-
|
58
|
-
if @options[:engine] == :sendmail
|
59
|
-
return sendmail
|
60
|
-
else
|
61
|
-
return send_smtp
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
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
|
68
|
-
def sendmail(options = nil)
|
69
|
-
merge_options(options) if options
|
70
|
-
|
71
|
-
prepare_email_message(options)
|
72
|
-
|
73
|
-
IO.popen(@options[:sendmail_path] || "/usr/sbin/sendmail -t","w") do |pipe|
|
74
|
-
pipe.puts(@options[:message])
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Attempts to send message using Net::SMTP.
|
79
|
-
def send_smtp(options = nil)
|
80
|
-
merge_options(options) if options
|
94
|
+
def send(new_options = {})
|
95
|
+
merge_options(new_options)
|
96
|
+
merge_options(@_controller.mailer_override)
|
81
97
|
|
82
|
-
prepare_email_message
|
83
|
-
|
84
|
-
require 'net/smtp' unless defined?(Net::SMTP)
|
85
|
-
# begin
|
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])
|
95
|
-
end
|
96
|
-
# rescue
|
97
|
-
# end
|
98
|
+
prepare_email_message
|
99
|
+
self.class.send(options)
|
98
100
|
end
|
99
101
|
end
|
100
102
|
end
|
data/lib/kiss/model.rb
CHANGED
@@ -4,26 +4,50 @@ 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
|
+
dsl_accessor :value_column, :display_column
|
8
|
+
|
7
9
|
def set_dataset(source)
|
8
10
|
super(source)
|
9
11
|
end
|
10
12
|
|
13
|
+
def has_many(*args)
|
14
|
+
one_to_many(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def belongs_to(*args)
|
18
|
+
many_to_one(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_and_belongs_to_many(*args)
|
22
|
+
many_to_many(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def alias_association(new_name, old_name)
|
26
|
+
alias_method new_name, old_name
|
27
|
+
alias_method :"#{new_name}_dataset", :"#{old_name}_dataset"
|
28
|
+
end
|
29
|
+
alias_method :alias_assoc, :alias_association
|
30
|
+
|
11
31
|
# This method is called by Sequel::Model's association def methods.
|
12
32
|
# Must return singularized table name for correct association key names.
|
13
33
|
def name
|
14
|
-
@
|
34
|
+
@_table.to_s.singularize
|
15
35
|
end
|
16
36
|
|
17
37
|
def controller
|
18
38
|
db.kiss_controller
|
19
39
|
end
|
20
40
|
|
41
|
+
def request
|
42
|
+
db.kiss_request || controller
|
43
|
+
end
|
44
|
+
|
21
45
|
def table
|
22
|
-
@
|
46
|
+
@_table.to_sym
|
23
47
|
end
|
24
48
|
|
25
49
|
def table=(table)
|
26
|
-
@
|
50
|
+
@_table = table
|
27
51
|
end
|
28
52
|
|
29
53
|
# Name symbol for default foreign key
|
@@ -40,7 +64,7 @@ class Kiss
|
|
40
64
|
opts = opts.clone
|
41
65
|
|
42
66
|
unless opts[:class] || opts[:class_name]
|
43
|
-
opts[:class_name] = name.to_s.
|
67
|
+
opts[:class_name] = name.to_s.pluralize
|
44
68
|
end
|
45
69
|
|
46
70
|
super(type, name, opts, &block)
|
@@ -49,53 +73,222 @@ class Kiss
|
|
49
73
|
end
|
50
74
|
|
51
75
|
include Kiss::ControllerAccessors
|
76
|
+
include Kiss::RequestAccessors
|
77
|
+
alias_method :database, :db
|
78
|
+
end
|
79
|
+
|
80
|
+
def deferred_associations
|
81
|
+
@deferred_associations ||= {}
|
52
82
|
end
|
53
83
|
|
54
|
-
def
|
55
|
-
|
84
|
+
def deferred_association_method_calls
|
85
|
+
@deferred_association_method_calls ||= []
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_associated_object(opts, o)
|
89
|
+
if o && !o.pk
|
90
|
+
if (da = deferred_associations[opts[:name]]) != o
|
91
|
+
if da
|
92
|
+
da.deferred_association_method_calls.delete_if {|c| c[1] == [self, opts.setter_method, da] }
|
93
|
+
remove_deferred_reciprocal_object(opts, o)
|
94
|
+
end
|
95
|
+
|
96
|
+
deferred_associations[opts[:name]] = o
|
97
|
+
o.deferred_association_method_calls << [false, [self, opts.setter_method, o]]
|
98
|
+
add_deferred_reciprocal_object(opts, o)
|
99
|
+
end
|
100
|
+
o
|
101
|
+
else
|
102
|
+
deferred_associations.delete(opts[:name])
|
103
|
+
super
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_associated_object(opts, o)
|
108
|
+
need_missing_opk = opts.need_associated_primary_key? && !o.pk
|
109
|
+
if !pk || need_missing_opk
|
110
|
+
double_defer = !pk && need_missing_opk
|
111
|
+
# TODO: add :uniq check here (and patch this in Sequel as well)
|
112
|
+
(deferred_associations[opts[:name]] ||= []).push(o)
|
113
|
+
|
114
|
+
method_call = [double_defer, [self, opts.add_method, o]]
|
115
|
+
deferred_association_method_calls << method_call unless pk
|
116
|
+
o.deferred_association_method_calls << method_call if need_missing_opk
|
117
|
+
|
118
|
+
add_deferred_reciprocal_object(opts, o)
|
119
|
+
o
|
120
|
+
else
|
121
|
+
deferred_associations[opts[:name]].delete(o) if deferred_associations[opts[:name]]
|
122
|
+
super
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Add/Set the current object to/as the given object's reciprocal association.
|
127
|
+
def add_deferred_reciprocal_object(opts, o)
|
128
|
+
return unless reciprocal = opts.reciprocal
|
129
|
+
if opts.reciprocal_array?
|
130
|
+
if array = o.deferred_associations[reciprocal] and !array.include?(self)
|
131
|
+
array.push(self)
|
132
|
+
end
|
133
|
+
else
|
134
|
+
o.deferred_associations[reciprocal] = self
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def load_associated_objects(opts, reload=false)
|
139
|
+
if d = deferred_associations[opts[:name]]
|
140
|
+
opts.returns_array? ? super + d : d
|
141
|
+
else
|
142
|
+
super || set_associated_object(opts, opts.associated_class.new)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Remove all associated objects from the given association
|
147
|
+
def remove_all_associated_objects(opts)
|
148
|
+
ret = super
|
149
|
+
if deferred_associations.include?(opts[:name])
|
150
|
+
def_ret = deferred_associations[opts[:name]].each do |o|
|
151
|
+
method_call = [self, opts.add_method, o]
|
152
|
+
deferred_association_method_calls.delete_if {|c| c[1] == method_call }
|
153
|
+
o.deferred_association_method_calls.delete_if {|c| c[1] == method_call }
|
154
|
+
remove_deferred_reciprocal_object(opts, o)
|
155
|
+
end
|
156
|
+
deferred_associations[opts[:name]] = []
|
157
|
+
(ret || []) + def_ret
|
158
|
+
else
|
159
|
+
ret
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Remove the given associated object from the given association
|
164
|
+
def remove_associated_object(opts, o)
|
165
|
+
if (array = deferred_associations[opts[:name]]) and array.delete(o)
|
166
|
+
method_call = [self, opts.add_method, o]
|
167
|
+
deferred_association_method_calls.delete_if {|c| c[1] == method_call }
|
168
|
+
o.deferred_association_method_calls.delete_if {|c| c[1] == method_call }
|
169
|
+
remove_deferred_reciprocal_object(opts, o)
|
170
|
+
else
|
171
|
+
super
|
172
|
+
end
|
173
|
+
o
|
174
|
+
end
|
175
|
+
|
176
|
+
# Remove/unset the current object from/as the given object's reciprocal association.
|
177
|
+
def remove_deferred_reciprocal_object(opts, o)
|
178
|
+
return unless reciprocal = opts.reciprocal
|
179
|
+
if opts.reciprocal_array?
|
180
|
+
if array = o.deferred_associations[reciprocal]
|
181
|
+
array.delete_if{|x| self === x}
|
182
|
+
end
|
183
|
+
else
|
184
|
+
o.deferred_associations[reciprocal] = nil
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def after_create
|
189
|
+
deferred_association_method_calls.each do |call|
|
190
|
+
if call[0]
|
191
|
+
# call[0] (double_defer) is true
|
192
|
+
# now set it to false, do nothing else
|
193
|
+
# (defer again until other side is created)
|
194
|
+
call[0] = false
|
195
|
+
else
|
196
|
+
m = call[1]
|
197
|
+
m.shift.send(*m) if m
|
198
|
+
end
|
199
|
+
end
|
200
|
+
@deferred_association_method_calls = []
|
201
|
+
end
|
202
|
+
|
203
|
+
def method_missing(meth, *args, &block)
|
204
|
+
if meth.to_s =~ /(\w+)\?\Z/
|
205
|
+
column = $1.to_sym
|
206
|
+
if respond_to?(column)
|
207
|
+
val = self.send(column, *args, &block)
|
208
|
+
return !(val.nil? || val.zero?)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
raise NoMethodError, "undefined method `#{meth}' for database model `#{self.class.name.pluralize}'"
|
56
212
|
end
|
57
213
|
|
58
214
|
def controller
|
59
215
|
self.class.controller
|
60
216
|
end
|
61
217
|
|
218
|
+
def request
|
219
|
+
self.class.request
|
220
|
+
end
|
221
|
+
|
222
|
+
def name
|
223
|
+
self[:name] || self.class.table.to_s.singularize.titleize
|
224
|
+
end
|
225
|
+
|
226
|
+
# Creates and invokes new Kiss::Mailer instance to send email message via SMTP.
|
227
|
+
def new_email(options = {})
|
228
|
+
request.new_email({
|
229
|
+
:data => self
|
230
|
+
}.merge(options))
|
231
|
+
end
|
232
|
+
|
233
|
+
def send_email(options = {})
|
234
|
+
new_email(options).send
|
235
|
+
end
|
236
|
+
|
237
|
+
def to_hash
|
238
|
+
result = {}
|
239
|
+
keys.each do |key|
|
240
|
+
result[key] = values[key]
|
241
|
+
end
|
242
|
+
result
|
243
|
+
end
|
244
|
+
|
62
245
|
include Kiss::ControllerAccessors
|
246
|
+
include Kiss::RequestAccessors
|
247
|
+
alias_method :database, :db
|
63
248
|
end
|
64
249
|
|
65
250
|
class ModelCache
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
251
|
+
def initialize(database, model_dir)
|
252
|
+
@_db = database
|
253
|
+
@_model_dir = model_dir
|
254
|
+
@_cache = {}
|
255
|
+
|
256
|
+
# TODO: Fix this to use file cache and subclass hierarchy, so models can be
|
257
|
+
# reloaded if _model.rb changes.
|
258
|
+
@_root_class = Class.new(Kiss::Model)
|
259
|
+
if File.exist?(filename = "#{@_model_dir}/_model.rb")
|
260
|
+
@_root_class.class_eval(File.read(filename), filename)
|
261
|
+
end
|
73
262
|
end
|
74
263
|
|
75
|
-
def new_model_class(database,source)
|
76
|
-
klass = Class.new(
|
264
|
+
def new_model_class(database, source)
|
265
|
+
klass = Class.new(@_root_class)
|
77
266
|
klass.set_dataset(database[source])
|
78
267
|
klass.table = source
|
268
|
+
klass.class_eval do
|
269
|
+
@_value_column = :id
|
270
|
+
@_display_column = :name
|
271
|
+
end
|
79
272
|
klass
|
80
273
|
end
|
81
274
|
|
82
275
|
def [](source)
|
83
276
|
raise 'argument to model cache must be symbol of database table name' unless source.is_a?(Symbol)
|
84
277
|
|
85
|
-
database = @
|
86
|
-
|
87
|
-
# use file_cache
|
88
|
-
model_path = "#{
|
89
|
-
|
90
|
-
klass = new_model_class(database,source)
|
91
|
-
klass.class_eval(src,model_path) if src
|
278
|
+
database = @_db
|
279
|
+
@_model_dir ? begin
|
280
|
+
# TODO: use request's file_cache
|
281
|
+
model_path = "#{@_model_dir}/#{source}.rb"
|
282
|
+
db.kiss_controller.file_cache(model_path) do |src|
|
283
|
+
klass = new_model_class(database, source)
|
284
|
+
klass.class_eval(src, model_path) if src
|
92
285
|
klass
|
93
286
|
end
|
94
|
-
end : @
|
287
|
+
end : @_cache[source] ||= new_model_class(database, source)
|
95
288
|
end
|
96
289
|
|
97
290
|
def database
|
98
|
-
@
|
291
|
+
@_db
|
99
292
|
end
|
100
293
|
alias_method :db, :database
|
101
294
|
|
@@ -103,16 +296,12 @@ class Kiss
|
|
103
296
|
Sequel::Model.dataset.literal(*args)
|
104
297
|
end
|
105
298
|
alias_method :quote, :literal
|
106
|
-
|
107
|
-
def mdy_to_ymd(*args)
|
108
|
-
Kiss.mdy_to_ymd(*args)
|
109
|
-
end
|
110
299
|
end
|
111
300
|
end
|
112
301
|
|
113
302
|
Sequel::Model::Associations::AssociationReflection.class_eval do
|
114
303
|
def associated_class
|
115
|
-
self[:class] ||= self[:model].controller.dbm[self[:class_name].to_s.pluralize.to_sym]
|
304
|
+
self[:class] ||= (self[:model].request || self[:model].controller).dbm[self[:class_name].to_s.pluralize.to_sym]
|
116
305
|
end
|
117
306
|
def default_left_key
|
118
307
|
:"#{self[:model].name.singularize.underscore}_id"
|
@@ -131,7 +320,7 @@ class Date
|
|
131
320
|
class << self
|
132
321
|
alias_method :old_parse, :parse
|
133
322
|
def parse(*args, &block)
|
134
|
-
return SequelZeroTime.new(args[0]) if args[0] =~ /0000/
|
323
|
+
return SequelZeroTime.new(args[0]) if args[0] =~ /0000-00-00/
|
135
324
|
old_parse(*args, &block)
|
136
325
|
end
|
137
326
|
end
|
@@ -184,12 +373,110 @@ end
|
|
184
373
|
class BigDecimal
|
185
374
|
# Formats number with comma-separated thousands.
|
186
375
|
def format_thousands(value = to_f.to_s)
|
187
|
-
integer, decimal = value.split(/\./,2)
|
188
|
-
integer.reverse.gsub(/(\d{3})/,'\1,').sub(/\,(-?)$/,'\1').reverse + '.' + decimal
|
376
|
+
integer, decimal = value.split(/\./, 2)
|
377
|
+
integer.reverse.gsub(/(\d{3})/, '\1,').sub(/\,(-?)$/, '\1').reverse + '.' + decimal
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
class SequelZeroTime < String
|
382
|
+
def initialize(value = '0000-00-00 00:00', *args, &block)
|
383
|
+
super(value, *args, &block)
|
189
384
|
end
|
190
385
|
|
191
|
-
#
|
192
|
-
def
|
193
|
-
|
386
|
+
# arithmetic operators
|
387
|
+
def +(*args)
|
388
|
+
self
|
389
|
+
end
|
390
|
+
def -(*args)
|
391
|
+
self
|
194
392
|
end
|
195
|
-
|
393
|
+
|
394
|
+
# comparision operators
|
395
|
+
def ==(value)
|
396
|
+
(value == 0 || value.is_a?(SequelZeroTime)) ? true : false
|
397
|
+
end
|
398
|
+
def >(value)
|
399
|
+
return false
|
400
|
+
end
|
401
|
+
def >=(value)
|
402
|
+
(value == 0 || value.is_a?(SequelZeroTime)) ? true : false
|
403
|
+
end
|
404
|
+
def <(value)
|
405
|
+
return true
|
406
|
+
end
|
407
|
+
def <=(value)
|
408
|
+
return true
|
409
|
+
end
|
410
|
+
|
411
|
+
# format conversion
|
412
|
+
def to_f; 0; end
|
413
|
+
def to_i; 0; end
|
414
|
+
def to_s; ''; end
|
415
|
+
|
416
|
+
# timezone conversion
|
417
|
+
def set_timezone!(zone, utc)
|
418
|
+
self
|
419
|
+
end
|
420
|
+
def from_timezone(zone)
|
421
|
+
self
|
422
|
+
end
|
423
|
+
def to_timezone(zone)
|
424
|
+
self
|
425
|
+
end
|
426
|
+
def to_utc
|
427
|
+
self
|
428
|
+
end
|
429
|
+
def zone
|
430
|
+
''
|
431
|
+
end
|
432
|
+
|
433
|
+
# string representations
|
434
|
+
def strftime(*args); ''; end
|
435
|
+
def md; ''; end
|
436
|
+
def md_full; ''; end
|
437
|
+
alias_method :md_long, :md_full
|
438
|
+
def mdy; ''; end
|
439
|
+
def mdy_full; ''; end
|
440
|
+
alias_method :mdy_long, :mdy_full
|
441
|
+
def mdy_hm; ''; end
|
442
|
+
def mdy_hmz; ''; end
|
443
|
+
def mdy_hms; ''; end
|
444
|
+
def mdy_hmsz; ''; end
|
445
|
+
def ymd_hm; ''; end
|
446
|
+
def ymd_hmz; ''; end
|
447
|
+
def ymd_hms; ''; end
|
448
|
+
def ymd_hmsz; ''; end
|
449
|
+
def sql; '0000-00-00 00:00'; end
|
450
|
+
def mdy_hm_full; ''; end
|
451
|
+
alias_method :mdy_hm_long, :mdy_hm_full
|
452
|
+
def mdy_hmz_full; ''; end
|
453
|
+
alias_method :mdy_hmz_long, :mdy_hmz_full
|
454
|
+
def hm; ''; end
|
455
|
+
def hmz; ''; end
|
456
|
+
def hms; ''; end
|
457
|
+
def hmsz; ''; end
|
458
|
+
def hm_mdy; ''; end
|
459
|
+
def hmz_mdy; ''; end
|
460
|
+
def hms_mdy; ''; end
|
461
|
+
def hmsz_mdy; ''; end
|
462
|
+
def hm_mdy_full; ''; end
|
463
|
+
alias_method :hm_mdy_long, :hm_mdy_full
|
464
|
+
def hmz_mdy_full; ''; end
|
465
|
+
alias_method :hmz_mdy_long, :hmz_mdy_full
|
466
|
+
|
467
|
+
def zero?; true; end
|
468
|
+
|
469
|
+
def in_between?(*args); false; end
|
470
|
+
end
|
471
|
+
|
472
|
+
IrregularInflection = proc do
|
473
|
+
def self.irregular(singular, plural)
|
474
|
+
singular(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + singular[1..-1])
|
475
|
+
plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
|
476
|
+
|
477
|
+
singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
|
478
|
+
plural(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + plural[1..-1])
|
479
|
+
end
|
480
|
+
end
|
481
|
+
Sequel::Inflections.class_eval &IrregularInflection
|
482
|
+
String::Inflections.class_eval &IrregularInflection
|