cramp 0.11 → 0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/lib/cramp.rb +12 -1
  2. data/lib/cramp/abstract.rb +72 -0
  3. data/lib/cramp/action.rb +12 -0
  4. data/lib/cramp/body.rb +48 -0
  5. data/lib/cramp/callbacks.rb +48 -0
  6. data/lib/cramp/keep_connection_alive.rb +19 -0
  7. data/lib/cramp/periodic_timer.rb +49 -0
  8. data/lib/cramp/rendering.rb +11 -0
  9. data/lib/cramp/test_case.rb +54 -0
  10. data/lib/cramp/websocket.rb +84 -0
  11. data/lib/cramp/{controller/websocket → websocket}/rainbows_backend.rb +1 -1
  12. data/lib/cramp/{controller/websocket → websocket}/thin_backend.rb +1 -1
  13. metadata +37 -86
  14. data/lib/cramp/controller.rb +0 -15
  15. data/lib/cramp/controller/abstract.rb +0 -71
  16. data/lib/cramp/controller/action.rb +0 -14
  17. data/lib/cramp/controller/body.rb +0 -50
  18. data/lib/cramp/controller/callbacks.rb +0 -50
  19. data/lib/cramp/controller/keep_connection_alive.rb +0 -21
  20. data/lib/cramp/controller/periodic_timer.rb +0 -51
  21. data/lib/cramp/controller/rendering.rb +0 -13
  22. data/lib/cramp/controller/test_case.rb +0 -57
  23. data/lib/cramp/controller/websocket.rb +0 -63
  24. data/lib/cramp/model.rb +0 -40
  25. data/lib/cramp/model/arel_monkey_patches.rb +0 -66
  26. data/lib/cramp/model/attribute.rb +0 -104
  27. data/lib/cramp/model/attribute_methods.rb +0 -83
  28. data/lib/cramp/model/base.rb +0 -119
  29. data/lib/cramp/model/callbacks.rb +0 -41
  30. data/lib/cramp/model/column.rb +0 -72
  31. data/lib/cramp/model/emysql_ext.rb +0 -21
  32. data/lib/cramp/model/engine.rb +0 -75
  33. data/lib/cramp/model/engine/connection.rb +0 -32
  34. data/lib/cramp/model/evented_mysql.rb +0 -298
  35. data/lib/cramp/model/finders.rb +0 -27
  36. data/lib/cramp/model/quoting.rb +0 -104
  37. data/lib/cramp/model/relation.rb +0 -62
  38. data/lib/cramp/model/status.rb +0 -18
@@ -1,41 +0,0 @@
1
- module Cramp
2
- module Model
3
- module Callbacks
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- class_inheritable_accessor :after_save_callback_names
8
- class_inheritable_accessor :after_destroy_callback_names
9
-
10
- self.after_save_callback_names = []
11
- self.after_destroy_callback_names = []
12
- end
13
-
14
- module ClassMethods
15
- def after_save(*method_names)
16
- self.after_save_callback_names += method_names
17
- end
18
-
19
- def after_destroy(*method_names)
20
- self.after_destroy_callback_names += method_names
21
- end
22
- end
23
-
24
- private
25
- def after_save_callbacks(result)
26
- after_save_callback_names.collect do |callback_name|
27
- callback = method callback_name
28
- callback.arity == 1 ? callback.call(result) : callback.call if callback
29
- end
30
- end
31
-
32
- def after_destroy_callbacks(result)
33
- after_destroy_callback_names.collect do |callback_name|
34
- callback = method callback_name
35
- callback.arity == 1 ? callback.call(result) : callback.call if callback
36
- end
37
- end
38
-
39
- end
40
- end
41
- end
@@ -1,72 +0,0 @@
1
- # Some of it yanked from Rails
2
-
3
- # Copyright (c) 2004-2009 David Heinemeier Hansson
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining
6
- # a copy of this software and associated documentation files (the
7
- # "Software"), to deal in the Software without restriction, including
8
- # without limitation the rights to use, copy, modify, merge, publish,
9
- # distribute, sublicense, and/or sell copies of the Software, and to
10
- # permit persons to whom the Software is furnished to do so, subject to
11
- # the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be
14
- # included in all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
-
24
- module Cramp
25
- module Model
26
- class Column < Struct.new(:name, :default, :sql_type, :null)
27
- attr_reader :type
28
-
29
- def initialize(name, default, sql_type, null)
30
- super
31
- @type = simplified_type(sql_type)
32
- end
33
-
34
- private
35
-
36
- def simplified_type(field_type)
37
- case field_type
38
- when /int/i
39
- :integer
40
- when /float|double/i
41
- :float
42
- when /decimal|numeric|number/i
43
- extract_scale(field_type) == 0 ? :integer : :decimal
44
- when /datetime/i
45
- :datetime
46
- when /timestamp/i
47
- :timestamp
48
- when /time/i
49
- :time
50
- when /date/i
51
- :date
52
- when /clob/i, /text/i
53
- :text
54
- when /blob/i, /binary/i
55
- :binary
56
- when /char/i, /string/i
57
- :string
58
- when /boolean/i
59
- :boolean
60
- end
61
- end
62
-
63
- def extract_scale(sql_type)
64
- case sql_type
65
- when /^(numeric|decimal|number)\((\d+)\)/i then 0
66
- when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
67
- end
68
- end
69
-
70
- end
71
- end
72
- end
@@ -1,21 +0,0 @@
1
- class EventedMysql
2
- def self.execute_now(query)
3
- @n ||= 0
4
- connection = connection_pool[@n]
5
- @n = 0 if (@n+=1) >= connection_pool.size
6
- connection.execute_now(query)
7
- end
8
-
9
- def execute_now(sql)
10
- log 'mysql sending', sql
11
- @mysql.query(sql)
12
- rescue Mysql::Error => e
13
- log 'mysql error', e.message
14
- if DisconnectErrors.include? e.message
15
- @@queue << [response, sql, cblk, eblk]
16
- return close
17
- else
18
- raise e
19
- end
20
- end
21
- end
@@ -1,75 +0,0 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
2
-
3
- module Cramp
4
- module Model
5
- class Engine
6
- autoload :Connection, "cramp/model/engine/connection"
7
-
8
- include Quoting
9
-
10
- def initialize(settings)
11
- @connection = Connection.new settings
12
- @quoted_column_names, @quoted_table_names = {}, {}
13
- end
14
-
15
- def create(relation, &block)
16
- query = relation.to_sql
17
- log_query(query)
18
- @connection.insert(query) {|rows| yield(rows) if block_given? }
19
- end
20
-
21
- def read(relation, &block)
22
- query = relation.to_sql
23
- log_query(query)
24
- @connection.select(query) {|rows| yield(rows) }
25
- end
26
-
27
- def update(relation)
28
- query = relation.to_sql
29
- log_query(query)
30
- @connection.update(query) {|rows| yield(rows) if block_given? }
31
- end
32
-
33
- def delete(relation)
34
- query = relation.to_sql
35
- log_query(query)
36
- @connection.delete(relation.to_sql) {|rows| yield(rows) if block_given? }
37
- end
38
-
39
- def adapter_name
40
- "mysql"
41
- end
42
-
43
- def connection
44
- # Arel apparently uses this method to check whether the engine is connected or not
45
- @connection
46
- end
47
-
48
- def tables
49
- sql = "SHOW TABLES"
50
- tables = []
51
- result = @connection.execute_now(sql)
52
-
53
- result.each { |field| tables << field[0] }
54
- result.free
55
- tables
56
- end
57
-
58
- def columns(table_name, name = nil)
59
- sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
60
- columns = []
61
- result = @connection.execute_now(sql)
62
-
63
- result.each { |field| columns << Column.new(field[0], field[4], field[1], field[2] == "YES") }
64
- result.free
65
- columns
66
- end
67
-
68
- protected
69
-
70
- def log_query(sql)
71
- Cramp.logger.info("[QUERY] #{sql}") if Cramp.logger
72
- end
73
- end
74
- end
75
- end
@@ -1,32 +0,0 @@
1
- module Cramp
2
- module Model
3
- class Engine
4
- class Connection
5
- def initialize(settings)
6
- EventedMysql.settings.update(settings)
7
- end
8
-
9
- def execute_now(sql)
10
- EventedMysql.execute_now sql
11
- end
12
-
13
- def insert(sql, &block)
14
- EventedMysql.insert sql, block
15
- end
16
-
17
- def select(sql, &block)
18
- EventedMysql.select sql, block
19
- end
20
-
21
- def update(sql, &block)
22
- EventedMysql.update sql, block
23
- end
24
-
25
- def delete(sql, &block)
26
- EventedMysql.delete sql, block
27
- end
28
-
29
- end
30
- end
31
- end
32
- end
@@ -1,298 +0,0 @@
1
- # Async MySQL driver for Ruby/EventMachine
2
- # (c) 2008 Aman Gupta (tmm1)
3
- # http://github.com/tmm1/em-mysql
4
-
5
- require 'eventmachine'
6
- require 'fcntl'
7
-
8
- class Mysql
9
- def result
10
- @cur_result
11
- end
12
- end
13
-
14
- class EventedMysql < EM::Connection
15
- def initialize mysql, opts
16
- @mysql = mysql
17
- @fd = mysql.socket
18
- @opts = opts
19
- @current = nil
20
- @@queue ||= []
21
- @processing = false
22
- @connected = true
23
-
24
- log 'mysql connected'
25
-
26
- self.notify_readable = true
27
- EM.add_timer(0){ next_query }
28
- end
29
- attr_reader :processing, :connected, :opts
30
- alias :settings :opts
31
-
32
- DisconnectErrors = [
33
- 'query: not connected',
34
- 'MySQL server has gone away',
35
- 'Lost connection to MySQL server during query'
36
- ] unless defined? DisconnectErrors
37
-
38
- def notify_readable
39
- log 'readable'
40
- if item = @current
41
- @current = nil
42
- start, response, sql, cblk, eblk = item
43
- log 'mysql response', Time.now-start, sql
44
- arg = case response
45
- when :raw
46
- result = @mysql.get_result
47
- @mysql.instance_variable_set('@cur_result', result)
48
- @mysql
49
- when :select
50
- ret = []
51
- result = @mysql.get_result
52
- result.each_hash{|h| ret << h }
53
- log 'mysql result', ret
54
- ret
55
- when :update
56
- result = @mysql.get_result
57
- @mysql.affected_rows
58
- when :insert
59
- result = @mysql.get_result
60
- @mysql.insert_id
61
- else
62
- result = @mysql.get_result
63
- log 'got a result??', result if result
64
- nil
65
- end
66
-
67
- @processing = false
68
- # result.free if result.is_a? Mysql::Result
69
- next_query
70
- cblk.call(arg) if cblk
71
- else
72
- log 'readable, but nothing queued?! probably an ERROR state'
73
- return close
74
- end
75
- rescue Mysql::Error => e
76
- log 'mysql error', e.message
77
- if e.message =~ /Deadlock/
78
- @@queue << [response, sql, cblk, eblk]
79
- @processing = false
80
- next_query
81
- elsif DisconnectErrors.include? e.message
82
- @@queue << [response, sql, cblk, eblk]
83
- return close
84
- elsif cb = (eblk || @opts[:on_error])
85
- cb.call(e)
86
- @processing = false
87
- next_query
88
- else
89
- raise e
90
- end
91
- # ensure
92
- # res.free if res.is_a? Mysql::Result
93
- # @processing = false
94
- # next_query
95
- end
96
-
97
- def unbind
98
- log 'mysql disconnect', $!
99
- # cp = EventedMysql.instance_variable_get('@connection_pool') and cp.delete(self)
100
- @connected = false
101
-
102
- # XXX wait for the next tick until the current fd is removed completely from the reactor
103
- #
104
- # XXX in certain cases the new FD# (@mysql.socket) is the same as the old, since FDs are re-used
105
- # XXX without next_tick in these cases, unbind will get fired on the newly attached signature as well
106
- #
107
- # XXX do _NOT_ use EM.next_tick here. if a bunch of sockets disconnect at the same time, we want
108
- # XXX reconnects to happen after all the unbinds have been processed
109
- EM.add_timer(0) do
110
- log 'mysql reconnecting'
111
- @processing = false
112
- @mysql = EventedMysql._connect @opts
113
- @fd = @mysql.socket
114
-
115
- @signature = EM.attach_fd @mysql.socket, true
116
- EM.set_notify_readable @signature, true
117
- log 'mysql connected'
118
- EM.instance_variable_get('@conns')[@signature] = self
119
- @connected = true
120
- make_socket_blocking
121
- next_query
122
- end
123
- end
124
-
125
- def execute sql, response = nil, cblk = nil, eblk = nil, &blk
126
- cblk ||= blk
127
-
128
- begin
129
- unless @processing or !@connected
130
- # begin
131
- # log 'mysql ping', @mysql.ping
132
- # # log 'mysql stat', @mysql.stat
133
- # # log 'mysql errno', @mysql.errno
134
- # rescue
135
- # log 'mysql ping failed'
136
- # @@queue << [response, sql, blk]
137
- # return close
138
- # end
139
-
140
- @processing = true
141
-
142
- log 'mysql sending', sql
143
- @mysql.send_query(sql)
144
- else
145
- @@queue << [response, sql, cblk, eblk]
146
- return
147
- end
148
- rescue Mysql::Error => e
149
- log 'mysql error', e.message
150
- if DisconnectErrors.include? e.message
151
- @@queue << [response, sql, cblk, eblk]
152
- return close
153
- else
154
- raise e
155
- end
156
- end
157
-
158
- log 'queuing', response, sql
159
- @current = [Time.now, response, sql, cblk, eblk]
160
- end
161
-
162
- def close
163
- @connected = false
164
- fd = detach
165
- log 'detached fd', fd
166
- end
167
-
168
- private
169
-
170
- def next_query
171
- if @connected and !@processing and pending = @@queue.shift
172
- response, sql, cblk, eblk = pending
173
- execute(sql, response, cblk, eblk)
174
- end
175
- end
176
-
177
- def log *args
178
- return unless @opts[:logging]
179
- p [Time.now, @fd, (@signature[-4..-1] if @signature), *args]
180
- end
181
-
182
- public
183
-
184
- def self.connect opts
185
- unless EM.respond_to?(:watch) and Mysql.method_defined?(:socket)
186
- raise RuntimeError, 'mysqlplus and EM.watch are required for EventedMysql'
187
- end
188
-
189
- if conn = _connect(opts)
190
- EM.watch conn.socket, self, conn, opts
191
- else
192
- EM.add_timer(5){ connect opts }
193
- end
194
- end
195
-
196
- self::Mysql = ::Mysql unless defined? self::Mysql
197
-
198
- # stolen from sequel
199
- def self._connect opts
200
- opts = settings.merge(opts)
201
-
202
- conn = Mysql.init
203
-
204
- # set encoding _before_ connecting
205
- if charset = opts[:charset] || opts[:encoding]
206
- conn.options(Mysql::SET_CHARSET_NAME, charset)
207
- end
208
-
209
- conn.options(Mysql::OPT_LOCAL_INFILE, 'client')
210
-
211
- conn.real_connect(
212
- opts[:host] || 'localhost',
213
- opts[:user] || opts[:username] || 'root',
214
- opts[:password],
215
- opts[:database],
216
- opts[:port],
217
- opts[:socket],
218
- 0 +
219
- # XXX multi results require multiple callbacks to parse
220
- # Mysql::CLIENT_MULTI_RESULTS +
221
- # Mysql::CLIENT_MULTI_STATEMENTS +
222
- (opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
223
- )
224
-
225
- # increase timeout so mysql server doesn't disconnect us
226
- # this is especially bad if we're disconnected while EM.attach is
227
- # still in progress, because by the time it gets to EM, the FD is
228
- # no longer valid, and it throws a c++ 'bad file descriptor' error
229
- # (do not use a timeout of -1 for unlimited, it does not work on mysqld > 5.0.60)
230
- conn.query("set @@wait_timeout = #{opts[:timeout] || 2592000}")
231
-
232
- # we handle reconnecting (and reattaching the new fd to EM)
233
- conn.reconnect = false
234
-
235
- # By default, MySQL 'where id is null' selects the last inserted id
236
- # Turn this off. http://dev.rubyonrails.org/ticket/6778
237
- conn.query("set SQL_AUTO_IS_NULL=0")
238
-
239
- # get results for queries
240
- conn.query_with_result = true
241
-
242
- conn
243
- rescue Mysql::Error => e
244
- if cb = opts[:on_error]
245
- cb.call(e)
246
- nil
247
- else
248
- raise e
249
- end
250
- end
251
- end
252
-
253
- class EventedMysql
254
- def self.settings
255
- @settings ||= { :connections => 4, :logging => false }
256
- end
257
-
258
- def self.execute query, type = nil, cblk = nil, eblk = nil, &blk
259
- unless nil#connection = connection_pool.find{|c| not c.processing and c.connected }
260
- @n ||= 0
261
- connection = connection_pool[@n]
262
- @n = 0 if (@n+=1) >= connection_pool.size
263
- end
264
-
265
- connection.execute(query, type, cblk, eblk, &blk)
266
- end
267
-
268
- %w[ select insert update delete raw ].each do |type| class_eval %[
269
-
270
- def self.#{type} query, cblk = nil, eblk = nil, &blk
271
- execute query, :#{type}, cblk, eblk, &blk
272
- end
273
-
274
- ] end
275
-
276
- def self.all query, type = nil, &blk
277
- responses = 0
278
- connection_pool.each do |c|
279
- c.execute(query, type) do
280
- responses += 1
281
- blk.call if blk and responses == @connection_pool.size
282
- end
283
- end
284
- end
285
-
286
- def self.connection_pool
287
- @connection_pool ||= (1..settings[:connections]).map{ EventedMysql.connect(settings) }
288
- # p ['connpool', settings[:connections], @connection_pool.size]
289
- # (1..(settings[:connections]-@connection_pool.size)).each do
290
- # @connection_pool << EventedMysql.connect(settings)
291
- # end unless settings[:connections] == @connection_pool.size
292
- # @connection_pool
293
- end
294
-
295
- def self.reset_connection_pool!
296
- @connection_pool = nil
297
- end
298
- end