cramp 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ module Cramp
2
+ module Controller
3
+ class Abstract
4
+
5
+ include Callbacks
6
+
7
+ class << self
8
+ def call(env)
9
+ controller = new(env).process
10
+ end
11
+ end
12
+
13
+ def initialize(env)
14
+ @env = env
15
+ end
16
+
17
+ def process
18
+ EM.next_tick { before_start }
19
+ ASYNC_RESPONSE
20
+ end
21
+
22
+ def continue
23
+ init_async_body
24
+
25
+ status, headers = respond_with
26
+ send_initial_response(status, headers, @body)
27
+
28
+ EM.next_tick { start } if respond_to?(:start)
29
+ EM.next_tick { on_start }
30
+ end
31
+
32
+ def respond_with
33
+ [200, {'Content-Type' => 'text/html'}]
34
+ end
35
+
36
+ def init_async_body
37
+ @body = Body.new
38
+
39
+ if self.class.on_finish_callbacks.any?
40
+ @body.callback { on_finish }
41
+ @body.errback { on_finish }
42
+ end
43
+ end
44
+
45
+ def finish
46
+ @body.succeed
47
+ end
48
+
49
+ def send_initial_response(response_status, response_headers, response_body)
50
+ EM.next_tick { @env['async.callback'].call [response_status, response_headers, response_body] }
51
+ end
52
+
53
+ def halt(status, headers = {}, halt_body = '')
54
+ send_initial_response(status, headers, halt_body)
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,22 @@
1
+ module Cramp
2
+ module Controller
3
+ class Action < Abstract
4
+
5
+ include PeriodicTimer
6
+ include KeepConnectionAlive
7
+
8
+ def request
9
+ @request ||= Rack::Request.new(@env)
10
+ end
11
+
12
+ def params
13
+ @params ||= @env['usher.params']
14
+ end
15
+
16
+ def render(body)
17
+ @body.call(body)
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -1,13 +1,15 @@
1
- # Copyright 2008 James Tucker <raggi@rubyforge.org>.
1
+ # Copyright 2008 James Tucker <raggi@rubyforge.org>.
2
2
 
3
3
  module Cramp
4
4
  module Controller
5
5
  class Body
6
-
7
6
  include EventMachine::Deferrable
8
7
 
9
8
  def initialize
10
9
  @queue = []
10
+
11
+ # Make sure to flush out the queue before closing the connection
12
+ callback { flush }
11
13
  end
12
14
 
13
15
  def call(body)
@@ -24,14 +26,21 @@ module Cramp
24
26
  @deferred_status != :unknown
25
27
  end
26
28
 
27
- private
29
+ def flush
30
+ return unless @body_callback
31
+
32
+ until @queue.empty?
33
+ @queue.shift.each {|chunk| @body_callback.call(chunk) }
34
+ end
35
+ end
28
36
 
29
37
  def schedule_dequeue
30
38
  return unless @body_callback
39
+
31
40
  EventMachine.next_tick do
32
41
  next unless body = @queue.shift
33
42
 
34
- body.each{|chunk| @body_callback.call(chunk) }
43
+ body.each {|chunk| @body_callback.call(chunk) }
35
44
  schedule_dequeue unless @queue.empty?
36
45
  end
37
46
  end
@@ -0,0 +1,58 @@
1
+ module Cramp
2
+ module Controller
3
+ module Callbacks
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ ASYNC_RESPONSE = [-1, {}, []].freeze
8
+ DEFAULT_STATUS = 200
9
+ DEFAULT_HEADERS = { 'Content-Type' => 'text/html' }.freeze
10
+
11
+ included do
12
+ class_inheritable_accessor :default_status, :default_headers, :instance_reader => false
13
+ self.default_status = DEFAULT_STATUS
14
+ self.default_headers = DEFAULT_HEADERS
15
+
16
+ class_inheritable_accessor :before_start_callbacks, :on_finish_callbacks, :on_start_callback, :instance_reader => false
17
+ self.before_start_callbacks = []
18
+ self.on_finish_callbacks = []
19
+ self.on_start_callback = []
20
+ end
21
+
22
+ module ClassMethods
23
+ def before_start(*methods)
24
+ self.before_start_callbacks += methods
25
+ end
26
+
27
+ def on_finish(*methods)
28
+ self.on_finish_callbacks += methods
29
+ end
30
+
31
+ def on_start(*methods)
32
+ self.on_start_callback += methods
33
+ end
34
+ end
35
+
36
+ def before_start(n = 0)
37
+ if callback = self.class.before_start_callbacks[n]
38
+ EM.next_tick { send(callback) { before_start(n+1) } }
39
+ else
40
+ continue
41
+ end
42
+ end
43
+
44
+ def on_start
45
+ self.class.on_start_callback.each do |callback|
46
+ EM.next_tick { send(callback) }
47
+ end
48
+ end
49
+
50
+ def on_finish
51
+ self.class.on_finish_callbacks.each do |callback|
52
+ EM.next_tick { send(callback) }
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ module Cramp
2
+ module Controller
3
+ module KeepConnectionAlive
4
+
5
+ extend ActiveSupport::Concern
6
+ include PeriodicTimer
7
+
8
+ module ClassMethods
9
+ def keep_connection_alive(options = {})
10
+ options = { :every => 15 }.merge(options)
11
+ periodic_timer :keep_connection_alive, options
12
+ end
13
+ end
14
+
15
+ def keep_connection_alive
16
+ render " "
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,51 @@
1
+ module Cramp
2
+ module Controller
3
+ module PeriodicTimer
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ class_inheritable_accessor :periodic_timers, :instance_reader => false
9
+ self.periodic_timers ||= []
10
+ end
11
+
12
+ module ClassMethods
13
+ def periodic_timer(method, options = {})
14
+ self.periodic_timers << [method, options]
15
+ end
16
+ end
17
+
18
+ def initialize(*)
19
+ super
20
+ @timers = []
21
+ end
22
+
23
+ def continue
24
+ super
25
+ EM.next_tick { start_periodic_timers }
26
+ end
27
+
28
+ def init_async_body
29
+ super
30
+
31
+ if self.class.periodic_timers.any?
32
+ @body.callback { stop_periodic_timers }
33
+ @body.errback { stop_periodic_timers }
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def start_periodic_timers
40
+ self.class.periodic_timers.each do |method, options|
41
+ @timers << EventMachine::PeriodicTimer.new(options[:every] || 1) { send(method) }
42
+ end
43
+ end
44
+
45
+ def stop_periodic_timers
46
+ @timers.each {|t| t.cancel }
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,13 @@
1
+ module Cramp
2
+ module Controller
3
+ module Rendering
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ def render(body)
8
+ @body.call(body)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,57 @@
1
+ require 'active_support'
2
+ require 'active_support/test_case'
3
+
4
+ module Cramp
5
+ module Controller
6
+ class TestCase < ::ActiveSupport::TestCase
7
+
8
+ setup :create_request
9
+
10
+ def create_request
11
+ @request = Rack::MockRequest.new(app)
12
+ end
13
+
14
+ def get(path, options = {}, headers = {}, &block)
15
+ callback = options.delete(:callback) || block
16
+ headers = headers.merge('async.callback' => callback)
17
+
18
+ EM.run { @request.get(path, headers) }
19
+ end
20
+
21
+ def get_body(path, options = {}, headers = {}, &block)
22
+ callback = options.delete(:callback) || block
23
+ response_callback = proc {|response| response[-1].each {|chunk| callback.call(chunk) } }
24
+ headers = headers.merge('async.callback' => response_callback)
25
+
26
+ EM.run { @request.get(path, headers) }
27
+ end
28
+
29
+ def get_body_chunks(path, options = {}, headers = {}, &block)
30
+ callback = options.delete(:callback) || block
31
+ count = options.delete(:count) || 1
32
+
33
+ stopping = false
34
+ chunks = []
35
+
36
+ get_body(path, options, headers) do |body_chunk|
37
+ chunks << body_chunk unless stopping
38
+
39
+ if chunks.count >= count
40
+ stopping = true
41
+ callback.call(chunks) if callback
42
+ EM.next_tick { EM.stop }
43
+ end
44
+ end
45
+ end
46
+
47
+ def app
48
+ raise "Please define a method called 'app' returning an async Rack Application"
49
+ end
50
+
51
+ def stop
52
+ EM.stop
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -1,14 +1,15 @@
1
- $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'vendor/activesupport/lib'))
2
- require 'active_support'
3
- require 'active_support/concern'
4
- require 'active_support/core_ext/hash/indifferent_access'
5
-
1
+ require 'cramp'
6
2
  require 'usher'
7
3
  require 'rack'
8
4
 
9
5
  module Cramp
10
6
  module Controller
11
- autoload :Base, "cramp/controller/base"
7
+ autoload :Action, "cramp/controller/action"
12
8
  autoload :Body, "cramp/controller/body"
9
+ autoload :PeriodicTimer, "cramp/controller/periodic_timer"
10
+ autoload :KeepConnectionAlive, "cramp/controller/keep_connection_alive"
11
+ autoload :Abstract, "cramp/controller/abstract"
12
+ autoload :Callbacks, "cramp/controller/callbacks"
13
+ autoload :TestCase, "cramp/controller/test_case"
13
14
  end
14
15
  end
@@ -0,0 +1,4 @@
1
+ module Kernel
2
+ alias :'_' :method
3
+ alias :callback :method
4
+ end
@@ -38,17 +38,21 @@ module Cramp
38
38
  @new_record
39
39
  end
40
40
 
41
- def save(&block)
41
+ def save(callback = nil, &block)
42
+ callback ||= block
43
+
42
44
  if valid?
43
- new_record? ? create_record(&block) : update_record(&block)
45
+ new_record? ? create_record(callback) : update_record(callback)
44
46
  else
45
- block.arity == 1 ? block.call(Status.new(self, false)) : block.call if block
47
+ callback.arity == 1 ? callback.call(Status.new(self, false)) : callback.call if callback
46
48
  end
47
49
  end
48
50
 
49
51
  private
50
52
 
51
- def create_record(&block)
53
+ def create_record(callback = nil, &block)
54
+ callback ||= block
55
+
52
56
  self.class.arel_table.insert(arel_attributes(true)) do |new_id|
53
57
  if new_id.present?
54
58
  self.id = new_id
@@ -58,15 +62,17 @@ module Cramp
58
62
  saved = false
59
63
  end
60
64
 
61
- block.arity == 1 ? block.call(Status.new(self, saved)) : block.call if block
65
+ callback.arity == 1 ? callback.call(Status.new(self, saved)) : callback.call if callback
62
66
  end
63
67
  end
64
68
 
65
- def update_record(&block)
69
+ def update_record(callback = nil, &block)
70
+ callback ||= block
71
+
66
72
  relation = self.class.arel_table.where(self.class[self.class.primary_key].eq(send(self.class.primary_key)))
67
73
 
68
74
  relation.update(arel_attributes) do |updated_rows|
69
- block.arity == 1 ? block.call(updated_rows) : block.call if block
75
+ callback.arity == 1 ? callback.call(updated_rows) : callback.call if callback
70
76
  end
71
77
  end
72
78
 
@@ -2,17 +2,7 @@ module Cramp
2
2
  module Model
3
3
  module Finders
4
4
 
5
- def all
6
- Relation.new(self, arel_table)
7
- end
8
-
9
- def first(&block)
10
- Relation.new(self, arel_table).limit(1).each(&block)
11
- end
12
-
13
- def where(relation)
14
- Relation.new(self, arel_table.where(relation))
15
- end
5
+ delegate :all, :first, :each, :where, :select, :group, :order, :limit, :offset, :to => :relation
16
6
 
17
7
  def [](attribute)
18
8
  arel_table[attribute]
@@ -22,6 +12,10 @@ module Cramp
22
12
  @arel_table ||= Arel::Table.new(table_name)
23
13
  end
24
14
 
15
+ def relation
16
+ Relation.new(self, arel_table)
17
+ end
18
+
25
19
  private
26
20
 
27
21
  def table_name
@@ -6,37 +6,39 @@ module Cramp
6
6
  @klass, @relation = klass, relation
7
7
  end
8
8
 
9
- def each(&block)
9
+ def each(callback = nil, &block)
10
+ callback ||= block
11
+
10
12
  @relation.each do |row|
11
13
  object = @klass.instantiate(row)
12
- block.call(object)
14
+ callback.call(object)
13
15
  end
14
16
  end
15
17
 
16
- def all(&block)
18
+ def all(callback = nil, &block)
19
+ callback ||= block
20
+
17
21
  @relation.all do |rows|
18
22
  objects = rows.map {|r| @klass.instantiate(r) }
19
- block.call(objects)
23
+ callback.call(objects)
20
24
  end
21
25
  end
22
26
 
23
- def first(&block)
27
+ def first(callback = nil, &block)
28
+ callback ||= block
29
+
24
30
  @relation.first do |row|
25
31
  object = row ? @klass.instantiate(row) : nil
26
- block.call(object)
32
+ callback.call(object)
27
33
  end
28
34
  end
29
35
 
30
- def select(selects)
31
- Relation.new(@klass, @relation.project(selects))
32
- end
33
-
34
- def where(conditions)
35
- Relation.new(@klass, @relation.where(conditions))
36
+ def where(*conditions)
37
+ Relation.new(@klass, @relation.where(*conditions))
36
38
  end
37
39
 
38
- def select(selects)
39
- Relation.new(@klass, @relation.project(selects))
40
+ def select(*selects)
41
+ Relation.new(@klass, @relation.project(*selects))
40
42
  end
41
43
 
42
44
  def group(groups)
@@ -2,6 +2,8 @@ module Cramp
2
2
  module Model
3
3
  class Status
4
4
 
5
+ attr_reader :record
6
+
5
7
  def initialize(record, success)
6
8
  @record = record
7
9
  @success = success
data/lib/cramp/model.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'cramp'
1
2
  require 'cramp/model/evented_mysql'
2
3
  require 'cramp/model/emysql_ext'
3
4
 
@@ -25,6 +26,14 @@ module Cramp
25
26
  Arel::Table.engine = Cramp::Model::Engine.new(settings)
26
27
  end
27
28
 
29
+ def self.select(query, callback = nil, &block)
30
+ callback ||= block
31
+
32
+ EventedMysql.select(query) do |rows|
33
+ callback.arity == 1 ? callback.call(rows) : callback.call if callback
34
+ end
35
+ end
36
+
28
37
  end
29
38
  end
30
39
 
data/lib/cramp.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  require 'eventmachine'
2
+ EM.epoll
2
3
 
3
4
  require 'active_support'
4
- require 'active_support/concern'
5
5
  require 'active_support/core_ext'
6
+ require 'active_support/concern'
7
+
8
+ require 'cramp/core_ext'
6
9
 
7
10
  module Cramp
8
- VERSION = '0.5'
11
+ VERSION = '0.6'
9
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cramp
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.5"
4
+ version: "0.6"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pratik Naik
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-23 00:00:00 +05:30
12
+ date: 2010-01-07 00:00:00 +05:30
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -93,9 +93,16 @@ extra_rdoc_files: []
93
93
  files:
94
94
  - README
95
95
  - MIT-LICENSE
96
- - lib/cramp/controller/base.rb
96
+ - lib/cramp/controller/abstract.rb
97
+ - lib/cramp/controller/action.rb
97
98
  - lib/cramp/controller/body.rb
99
+ - lib/cramp/controller/callbacks.rb
100
+ - lib/cramp/controller/keep_connection_alive.rb
101
+ - lib/cramp/controller/periodic_timer.rb
102
+ - lib/cramp/controller/rendering.rb
103
+ - lib/cramp/controller/test_case.rb
98
104
  - lib/cramp/controller.rb
105
+ - lib/cramp/core_ext.rb
99
106
  - lib/cramp/model/arel_monkey_patches.rb
100
107
  - lib/cramp/model/attribute.rb
101
108
  - lib/cramp/model/attribute_methods.rb
@@ -1,114 +0,0 @@
1
- module Cramp
2
- module Controller
3
- class Base
4
- ASYNC_RESPONSE = [-1, {}, []]
5
-
6
- DEFAULT_STATUS = 200
7
- DEFAULT_HEADERS = { 'Content-Type' => 'text/html' }
8
-
9
- def self.call(env)
10
- controller = new(env).process
11
- end
12
-
13
- def self.set_default_response(status = 200, headers = DEFAULT_HEADERS)
14
- @@default_status = 200
15
- @@default_headers = headers
16
- end
17
-
18
- def self.default_status
19
- defined?(@@default_status) ? @@default_status : DEFAULT_STATUS
20
- end
21
-
22
- def self.default_headers
23
- defined?(@@default_headers) ? @@default_headers : DEFAULT_HEADERS
24
- end
25
-
26
- def self.periodic_timer(method, options = {})
27
- @@periodic_timers ||= []
28
- @@periodic_timers << [method, options]
29
- end
30
-
31
- def self.periodic_timers
32
- defined?(@@periodic_timers) ? @@periodic_timers : []
33
- end
34
-
35
- def self.keep_connection_alive(options = {})
36
- options = { :every => 30 }.merge(options)
37
- periodic_timer :keep_connection_alive, options
38
- end
39
-
40
- def initialize(env)
41
- @env = env
42
- @timers = []
43
- end
44
-
45
- def process
46
- EM.next_tick { before_start }
47
- ASYNC_RESPONSE
48
- end
49
-
50
- def request
51
- @request ||= Rack::Request.new(@env)
52
- end
53
-
54
- def params
55
- @params ||= @env['usher.params']
56
- end
57
-
58
- def render(body)
59
- @body.call(body)
60
- end
61
-
62
- def send_initial_response(response_status, response_headers, response_body)
63
- EM.next_tick { @env['async.callback'].call [response_status, response_headers, response_body] }
64
- end
65
-
66
- def finish
67
- EM.next_tick { @body.succeed }
68
- end
69
-
70
- def before_start
71
- continue
72
- end
73
-
74
- def halt(status, headers = self.class.default_headers, halt_body = '')
75
- send_initial_response(status, headers, halt_body)
76
- end
77
-
78
- def continue
79
- init_async_body
80
- send_initial_response(self.class.default_status, self.class.default_headers, @body)
81
-
82
- EM.next_tick { start_periodic_timers }
83
- EM.next_tick { start } if respond_to?(:start)
84
- end
85
-
86
- def init_async_body
87
- @body = Body.new
88
- @body.callback { on_finish }
89
- @body.errback { on_finish }
90
-
91
- @body.callback { stop_periodic_timers }
92
- @body.errback { stop_periodic_timers }
93
- end
94
-
95
- def start_periodic_timers
96
- self.class.periodic_timers.each do |method, options|
97
- @timers << EventMachine::PeriodicTimer.new(options[:every] || 1) { send(method) }
98
- end
99
- end
100
-
101
- def stop_periodic_timers
102
- @timers.each {|t| t.cancel }
103
- end
104
-
105
- def on_finish
106
- end
107
-
108
- def keep_connection_alive
109
- render " "
110
- end
111
-
112
- end
113
- end
114
- end