cramp 0.5 → 0.6

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.
@@ -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