kiss 1.1 → 1.7
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/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
|