communicator 0.1.0 → 0.1.1

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/Gemfile.lock CHANGED
@@ -6,6 +6,7 @@ PATH
6
6
  httparty (>= 0.6.1)
7
7
  json (>= 1.4.0)
8
8
  sinatra (~> 1.1.0)
9
+ sinatra-basic-auth
9
10
 
10
11
  GEM
11
12
  remote: http://rubygems.org/
@@ -25,6 +26,8 @@ GEM
25
26
  sinatra (1.1.0)
26
27
  rack (~> 1.1)
27
28
  tilt (~> 1.1)
29
+ sinatra-basic-auth (0.1.0)
30
+ sinatra
28
31
  sqlite3-ruby (1.3.2)
29
32
  tilt (1.1)
30
33
 
@@ -41,4 +44,5 @@ DEPENDENCIES
41
44
  rack-test (>= 0.5.6)
42
45
  shoulda (= 2.10.3)
43
46
  sinatra (~> 1.1.0)
47
+ sinatra-basic-auth
44
48
  sqlite3-ruby (>= 1.3.0)
data/README.rdoc CHANGED
@@ -59,6 +59,11 @@ class receives updates from like this:
59
59
  class Post < ActiveRecord::Base
60
60
  receives_from :post
61
61
  end
62
+
63
+ If you want to skip some remote attributes and not let them progapate into local instances,
64
+ use `receives_from :post, :except => [:user_id]`.
65
+
66
+ Attributes that are not physically present in the local database will be skipped automatically.
62
67
 
63
68
  Use the automatically added `publish` instance method on your models to push changes
64
69
  to the other side. They will be enqueued in the local `outbound_messages` table and
data/Rakefile CHANGED
@@ -54,7 +54,10 @@ namespace :test_server do
54
54
  Thread.new do
55
55
  # Capture sinatra output (to hide it away...)
56
56
  require "open3"
57
- Open3.popen3("bundle exec rackup test/config.ru -p 20359 --pid=#{File.join(File.dirname(__FILE__), 'test', 'rack.pid')}")
57
+ rackup = "bundle exec rackup test/config.ru -p 20359 --pid=#{File.join(File.dirname(__FILE__), 'test', 'rack.pid')}"
58
+ Open3.popen3(rackup)
59
+ #`#{rackup}` # Uncomment to see actual server output
60
+
58
61
  end
59
62
  sleep 2.0
60
63
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
data/communicator.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{communicator}
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Christoph Olszowka"]
@@ -39,11 +39,14 @@ Gem::Specification.new do |s|
39
39
  "test/config.ru",
40
40
  "test/factories.rb",
41
41
  "test/helper.rb",
42
+ "test/lib/comment.rb",
42
43
  "test/lib/post.rb",
44
+ "test/lib/test_server_database/comment.rb",
43
45
  "test/lib/test_server_database/inbound_message.rb",
44
46
  "test/lib/test_server_database/outbound_message.rb",
45
47
  "test/lib/test_server_database/post.rb",
46
48
  "test/migrate/20101101093519_create_posts.rb",
49
+ "test/migrate/20101103120519_create_comments.rb",
47
50
  "test/test_client.rb",
48
51
  "test/test_message_models.rb",
49
52
  "test/test_server.rb"
@@ -56,11 +59,14 @@ Gem::Specification.new do |s|
56
59
  s.test_files = [
57
60
  "test/factories.rb",
58
61
  "test/helper.rb",
62
+ "test/lib/comment.rb",
59
63
  "test/lib/post.rb",
64
+ "test/lib/test_server_database/comment.rb",
60
65
  "test/lib/test_server_database/inbound_message.rb",
61
66
  "test/lib/test_server_database/outbound_message.rb",
62
67
  "test/lib/test_server_database/post.rb",
63
68
  "test/migrate/20101101093519_create_posts.rb",
69
+ "test/migrate/20101103120519_create_comments.rb",
64
70
  "test/test_client.rb",
65
71
  "test/test_message_models.rb",
66
72
  "test/test_server.rb"
@@ -8,8 +8,18 @@ module Communicator::ActiveRecordIntegration
8
8
  # receives_from :post
9
9
  # end
10
10
  #
11
- def receives_from(source)
12
- Communicator.register_receiver(self, source)
11
+ def receives_from(source, options={})
12
+ Communicator.register_receiver(self, source, options)
13
+ end
14
+
15
+ def skipped_remote_attributes
16
+ @skipped_remote_attributes ||= []
17
+ end
18
+
19
+ def skip_remote_attributes(*attr_names)
20
+ attr_names.each do |attr_name|
21
+ skipped_remote_attributes << attr_name.to_sym
22
+ end
13
23
  end
14
24
  end
15
25
 
@@ -24,11 +34,13 @@ module Communicator::ActiveRecordIntegration
24
34
  end
25
35
 
26
36
  # Processes the given message body by applying all contained attributes and their values
27
- # and saving
37
+ # and saving. When the setter instance method is missing on the local record, skip that attribute.
28
38
  def process_message(input)
29
39
  # When the input is still json, parse it. Otherwise we're assuming it's already a demarshalled hash
30
40
  input = JSON.parse(input) if input.kind_of?(String)
31
41
  input.each do |attr_name, value|
42
+ # Exclude skipped attributes
43
+ next if self.class.skipped_remote_attributes.include?(attr_name.to_sym) or !attributes.has_key?(attr_name)
32
44
  self.send("#{attr_name}=", value)
33
45
  end
34
46
  self.updated_from_message = true
@@ -16,12 +16,28 @@ class Communicator::Server < Sinatra::Base
16
16
  end
17
17
  end
18
18
 
19
- use Rack::Auth::Basic do |username, password|
20
- [username, password] == [Communicator::Server.username, Communicator::Server.password]
19
+ # use Rack::Auth::Basic do |username, password|
20
+ # [username, password] == [Communicator::Server.username, Communicator::Server.password]
21
+ # end
22
+
23
+ helpers do
24
+ def protected!
25
+ unless authorized?
26
+ response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth")
27
+ throw(:halt, [401, "Not authorized\n"])
28
+ end
29
+ end
30
+
31
+ def authorized?
32
+ @auth ||= Rack::Auth::Basic::Request.new(request.env)
33
+ @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [Communicator::Server.username, Communicator::Server.password]
34
+ end
21
35
  end
36
+
22
37
 
23
38
  # PULL
24
39
  get '/messages.json' do
40
+ protected!
25
41
  # Require from_id attribute
26
42
  return [409, "Specify from_id!"] unless params[:from_id]
27
43
 
@@ -39,6 +55,8 @@ class Communicator::Server < Sinatra::Base
39
55
 
40
56
  # PUSH
41
57
  post '/messages.json' do
58
+ protected!
59
+
42
60
  body = request.body.read.strip
43
61
  # Make sure a message body is given!
44
62
  return [409, "No data given"] if body.length < 2
data/lib/communicator.rb CHANGED
@@ -20,15 +20,28 @@ module Communicator
20
20
  # Register a given class as a receiver from source (underscored name). Will then
21
21
  # mix in the instance methods from Communicator::ActiveRecord::InstanceMethods so
22
22
  # message processing and publishing functionality is included
23
- def register_receiver(target, source)
23
+ def register_receiver(target, source, options={})
24
24
  receivers[source] = target
25
25
  target.send(:include, Communicator::ActiveRecordIntegration::InstanceMethods)
26
+
27
+ target.skip_remote_attributes(*options[:except]) if options[:except]
28
+
29
+ target
26
30
  end
27
31
 
28
32
  # Tries to find the receiver for given source, raising Communicator::ReceiverUnknown
29
33
  # on failure
30
34
  def receiver_for(source)
31
35
  return receivers[source] if receivers[source]
36
+
37
+ # If not found in the first place, maybe the class just isn't loaded yet and
38
+ # thus hasn't registered - let's require all models and try again
39
+ if defined?(Rails)
40
+ Dir[File.join(Rails.root, 'app/models/**/*.rb')].each {|model| require model}
41
+ return receivers[source] if receivers[source]
42
+ end
43
+
44
+ # When everything else fails, just throw an exception...
32
45
  raise Communicator::ReceiverUnknown.new("No receiver registered for '#{source}'")
33
46
  end
34
47
  end
data/test/config.ru CHANGED
@@ -9,6 +9,7 @@ require 'communicator'
9
9
 
10
10
  ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => "db/test_server.sqlite3")
11
11
  require 'lib/post'
12
+ require 'lib/comment'
12
13
 
13
14
  Communicator::Server.username = 'testuser'
14
15
  Communicator::Server.password = 'pwd'
data/test/helper.rb CHANGED
@@ -16,12 +16,14 @@ require 'factories'
16
16
  # Connect to client test database
17
17
  ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => "db/test_client.sqlite3")
18
18
  require 'lib/post'
19
+ require 'lib/comment'
19
20
 
20
21
  # Connect to server database too so we can peek into what's happening over there
21
22
  class TestServerDatabase < ActiveRecord::Base
22
23
  establish_connection(:adapter => 'sqlite3', :database => "db/test_server.sqlite3")
23
24
  end
24
25
  require 'lib/test_server_database/post'
26
+ require 'lib/test_server_database/comment'
25
27
  require 'lib/test_server_database/inbound_message'
26
28
  require 'lib/test_server_database/outbound_message'
27
29
 
@@ -39,9 +41,11 @@ class Test::Unit::TestCase
39
41
  Communicator::InboundMessage.delete_all
40
42
  Communicator::OutboundMessage.delete_all
41
43
  Post.delete_all
44
+ Comment.delete_all
42
45
 
43
46
  TestServerDatabase::InboundMessage.delete_all
44
47
  TestServerDatabase::OutboundMessage.delete_all
45
48
  TestServerDatabase::Post.delete_all
49
+ TestServerDatabase::Comment.delete_all
46
50
  end
47
51
  end
@@ -0,0 +1,7 @@
1
+ # A simple class for publishing and receiving messages
2
+ class Comment < ActiveRecord::Base
3
+ receives_from :comment, :except => [:title]
4
+ after_save do |r|
5
+ r.publish unless r.updated_from_message
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # Basic class for introspection of what is happening on the server side
2
+ class TestServerDatabase::Comment < TestServerDatabase
3
+ set_table_name "comments"
4
+ end
@@ -0,0 +1,13 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :comments do |t|
4
+ t.string :title, :default => nil
5
+ t.text :body, :null => false
6
+ t.timestamps
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :comments
12
+ end
13
+ end
data/test/test_client.rb CHANGED
@@ -121,6 +121,22 @@ class TestClient < Test::Unit::TestCase
121
121
  end
122
122
  end
123
123
 
124
+ # Make sure attributes skipped with :except are not saved at remote
125
+ context "PUSHing a new comment" do
126
+ setup do
127
+ assert @comment = Comment.create(:title => 'my comment', :body => 'some comment')
128
+ Communicator::Client.push
129
+ end
130
+
131
+ should "have created the comment at remote" do
132
+ assert_equal 'some comment', TestServerDatabase::Comment.first.body
133
+ end
134
+
135
+ should "have skipped permissions attribute when processing at remote" do
136
+ assert_nil TestServerDatabase::Comment.first.title
137
+ end
138
+ end
139
+
124
140
  context "when an update message is created at remote" do
125
141
  setup do
126
142
  @remote_msg = TestServerDatabase::OutboundMessage.create!(:body => {:post => {:id => 25, :title => 'new title', :body => 'remote body'}}.to_json)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: communicator
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Christoph Olszowka
@@ -194,11 +194,14 @@ files:
194
194
  - test/config.ru
195
195
  - test/factories.rb
196
196
  - test/helper.rb
197
+ - test/lib/comment.rb
197
198
  - test/lib/post.rb
199
+ - test/lib/test_server_database/comment.rb
198
200
  - test/lib/test_server_database/inbound_message.rb
199
201
  - test/lib/test_server_database/outbound_message.rb
200
202
  - test/lib/test_server_database/post.rb
201
203
  - test/migrate/20101101093519_create_posts.rb
204
+ - test/migrate/20101103120519_create_comments.rb
202
205
  - test/test_client.rb
203
206
  - test/test_message_models.rb
204
207
  - test/test_server.rb
@@ -239,11 +242,14 @@ summary: Data push/pull between apps with local inbound/outbound queue and easy
239
242
  test_files:
240
243
  - test/factories.rb
241
244
  - test/helper.rb
245
+ - test/lib/comment.rb
242
246
  - test/lib/post.rb
247
+ - test/lib/test_server_database/comment.rb
243
248
  - test/lib/test_server_database/inbound_message.rb
244
249
  - test/lib/test_server_database/outbound_message.rb
245
250
  - test/lib/test_server_database/post.rb
246
251
  - test/migrate/20101101093519_create_posts.rb
252
+ - test/migrate/20101103120519_create_comments.rb
247
253
  - test/test_client.rb
248
254
  - test/test_message_models.rb
249
255
  - test/test_server.rb