hayeah-ASS 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/ASS.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ASS}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Howard Yeh"]
9
+ s.date = %q{2009-08-13}
10
+ s.email = %q{hayeah@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.textile"
14
+ ]
15
+ s.files = [
16
+ "ASS.gemspec",
17
+ "LICENSE",
18
+ "README.textile",
19
+ "Rakefile",
20
+ "VERSION.yml",
21
+ "lib/ass.rb",
22
+ "test/ass_test.rb",
23
+ "test/test_helper.rb"
24
+ ]
25
+ s.has_rdoc = true
26
+ s.homepage = %q{http://github.com/hayeah/ass}
27
+ s.rdoc_options = ["--charset=UTF-8"]
28
+ s.require_paths = ["lib"]
29
+ s.rubygems_version = %q{1.3.1}
30
+ s.summary = %q{Asynchronous Service Stages for Distributed Services}
31
+ s.test_files = [
32
+ "test/ass_test.rb",
33
+ "test/test_helper.rb"
34
+ ]
35
+
36
+ if s.respond_to? :specification_version then
37
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
38
+ s.specification_version = 2
39
+
40
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
41
+ s.add_runtime_dependency(%q<amqp>, [">= 0"])
42
+ else
43
+ s.add_dependency(%q<amqp>, [">= 0"])
44
+ end
45
+ else
46
+ s.add_dependency(%q<amqp>, [">= 0"])
47
+ end
48
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Howard Yeh
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ASS"
8
+ gem.summary = "Asynchronous Service Stages for Distributed Services"
9
+ gem.email = "hayeah@gmail.com"
10
+ gem.homepage = "http://github.com/hayeah/ass"
11
+ gem.authors = ["Howard Yeh"]
12
+ gem.add_dependency "amqp"
13
+ gem.files = FileList["[A-Z]*", "{lib,test}/**/*"]
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ rescue LoadError
17
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/*_test.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+
41
+ task :default => :test
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ if File.exist?('VERSION.yml')
46
+ config = YAML.load(File.read('VERSION.yml'))
47
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "ass #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
57
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
data/lib/ass.rb ADDED
@@ -0,0 +1,212 @@
1
+ require 'mq'
2
+ class Ass
3
+
4
+ attr_reader :server_exchange
5
+
6
+ def self.declare(server_exchange)
7
+ self.new([server_exchange,{:passive => true}])
8
+ end
9
+
10
+ # uh... we'll assume that the exchanges are all direct exchanges.
11
+ def initialize(server_exchange)
12
+ @server_exchange = get_exchange(server_exchange)
13
+ end
14
+
15
+ def client(client_exchange,*args)
16
+ @client_exchange ||= get_exchange(client_exchange)
17
+ q = get_queue(@client_exchange,*args)
18
+ Client.new(@server_exchange,@client_exchange,q)
19
+ end
20
+
21
+ def server(*args)
22
+ Server.new(@server_exchange,get_queue(@server_exchange,*args))
23
+ end
24
+
25
+ def get_exchange(arg)
26
+ case arg
27
+ when Array
28
+ exchanges = exchange[0]
29
+ opts = exchange[1]
30
+ else
31
+ exchange = arg
32
+ opts = nil
33
+ end
34
+ opts = {} if opts.nil?
35
+ exchange = exchange.is_a?(MQ::Exchange) ? exchange : MQ.direct(exchange,opts)
36
+ raise "accepts only direct exchanges" unless exchange.type == :direct
37
+ exchange
38
+ end
39
+
40
+ # can specify a key to create a queue for that subdomain
41
+ def get_queue(exchange,*args)
42
+ case args[0]
43
+ when Hash
44
+ key = nil
45
+ opts = args[0]
46
+ when String
47
+ key = args[0]
48
+ opts = args[1]
49
+ end
50
+ opts = {} if opts.nil?
51
+ if key
52
+ name = "#{exchange.name}--#{key}"
53
+ q = MQ.queue(name,opts)
54
+ q.bind(exchange,{ :routing_key => key})
55
+ else
56
+ q = MQ.queue(exchange.name,opts)
57
+ q.bind(exchange,{ :routing_key => exchange.name })
58
+ end
59
+ q
60
+ end
61
+
62
+ module Callback
63
+
64
+ def build_callback_klass(callback)
65
+ case callback
66
+ when Proc
67
+ Class.new &callback
68
+ when Class
69
+ callback
70
+ when Module
71
+ Class.new { include callback }
72
+ end
73
+ end
74
+
75
+ def callback(info,payload)
76
+ # method,data,meta
77
+ if @callback_klass.respond_to? :version
78
+ klass = @callback_klass.get_version(payload[:version])
79
+ else
80
+ klass = @callback_klass
81
+ end
82
+ obj = klass.new
83
+ service = self
84
+ obj.instance_variable_set("@__service__",service)
85
+ obj.instance_variable_set("@__header__",info)
86
+ obj.instance_variable_set("@__meta__",payload[:meta])
87
+ class << obj
88
+ def header
89
+ @__header__
90
+ end
91
+
92
+ def meta
93
+ @__meta__
94
+ end
95
+
96
+ def service
97
+ @__service__
98
+ end
99
+
100
+ def call(method,data=nil,meta=nil,opts={})
101
+ @__service__.call(method,data,meta,opts)
102
+ end
103
+ end
104
+ #p [:call,payload]
105
+ obj.send(payload[:method],
106
+ payload[:data])
107
+ end
108
+ end
109
+
110
+ class Client
111
+ include Callback
112
+ def initialize(server_exchange,client_exchange,queue)
113
+ @server_exchange = server_exchange
114
+ @client_exchange = client_exchange
115
+ @queue = queue
116
+ end
117
+
118
+ def react(callback=nil,opts=nil,&block)
119
+ if block
120
+ opts = callback
121
+ callback = block
122
+ end
123
+ opts = {} if opts.nil?
124
+
125
+ @callback_klass = build_callback_klass(callback)
126
+ @ack = opts[:ack]
127
+ @queue.subscribe(opts) do |info,payload|
128
+ payload = ::Marshal.load(payload)
129
+ callback(info,payload)
130
+ info.ack if @ack
131
+ end
132
+ self
133
+ end
134
+
135
+ def call(method,data=nil,meta=nil,opts={})
136
+ # opts passed to publish
137
+ # if no routing key is given, use receiver's name as the routing key.
138
+ version = @klass.version if @klass.respond_to? :version
139
+ payload = {
140
+ :method => method,
141
+ :data => data,
142
+ :meta => meta,
143
+ :version => version
144
+ }
145
+
146
+ # set it up s.t. server would respond to
147
+ # private queue if key is given, otherwise
148
+ # the server would respond to public queue.
149
+ key = opts.delete(:key)
150
+ @server_exchange.publish Marshal.dump(payload), {
151
+ :key => (key ? key : @server_exchange.name),
152
+ :reply_to => @client_exchange.name
153
+ }.merge(opts)
154
+ end
155
+
156
+ # for casting, just null the reply_to field, so server doesn't respond.
157
+ def cast(method,data=nil,meta=nil,opts={})
158
+ self.call(method,data,meta,opts.merge({:reply_to => nil}))
159
+ end
160
+
161
+
162
+ end
163
+
164
+ class Server
165
+ include Callback
166
+
167
+ def initialize(server_exchange,q)
168
+ @queue = q
169
+ @server_exchange = server_exchange
170
+ end
171
+
172
+ attr_reader :queue
173
+ def exchange
174
+ @server_exchange
175
+ end
176
+
177
+ def react(callback=nil,opts=nil,&block)
178
+ if block
179
+ opts = callback
180
+ callback = block
181
+ end
182
+ opts = {} if opts.nil?
183
+
184
+ @callback_klass = build_callback_klass(callback)
185
+ @ack = opts[:ack]
186
+ @queue.subscribe(opts) do |info,payload|
187
+ payload = ::Marshal.load(payload)
188
+ #p [info,info.reply_to,payload]
189
+ data2 = callback(info,payload)
190
+ payload2 = payload.merge :data => data2
191
+ if info.routing_key == @server_exchange.name
192
+ # addressed to the server's public
193
+ # queue, respond to the routing_key of
194
+ # the client's public queue.
195
+ key = info.reply_to
196
+ else
197
+ # addressed to the private queue
198
+ key = info.routing_key
199
+ end
200
+ MQ.direct(info.reply_to).publish(::Marshal.dump(payload2),:routing_key => key) if info.reply_to
201
+ info.ack if @ack
202
+ end
203
+ self
204
+ end
205
+ end
206
+
207
+ class Peeper
208
+ def initialize(exchange,callback)
209
+ # create a temporary queue that binds to an exchange
210
+ end
211
+ end
212
+ end
data/test/ass_test.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class AssTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'ass'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hayeah-ASS
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Howard Yeh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: amqp
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: hayeah@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.textile
34
+ files:
35
+ - ASS.gemspec
36
+ - LICENSE
37
+ - README.textile
38
+ - Rakefile
39
+ - VERSION.yml
40
+ - lib/ass.rb
41
+ - test/ass_test.rb
42
+ - test/test_helper.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/hayeah/ass
45
+ licenses:
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: Asynchronous Service Stages for Distributed Services
70
+ test_files:
71
+ - test/ass_test.rb
72
+ - test/test_helper.rb