active_remote 2.0.2 → 2.1.0.beta1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8da0d6b9a19c100a7c36a11ef650e1d788f4b493
4
- data.tar.gz: 1da175673f70cbd2eed8686fb27447d19c51b222
3
+ metadata.gz: 0dd96c99847eae8cf17cec819377a356b0c9fe51
4
+ data.tar.gz: 97353c96fb186aaa0c509b882bb860389656c2c0
5
5
  SHA512:
6
- metadata.gz: 864b2fa737f45a1a8988b40aaace637c8ded669f4012f0a49d892fb325cbf42cb1acfbef159d3b09443de7328082b342f950ea37abc7f375d2a83ede46a5b77f
7
- data.tar.gz: 7120238fbe22ca117d738b76f95625eb78c91e1cb52070d6d2c7a41933ce4c952deaaa61c0968352ae3f645807f559e8ff1a97f1087a660b5da1db2c8bff2e7c
6
+ metadata.gz: ad36c87d5dd76cd1663e82f43b92dde4b9780b60033f2cc59ee9d925ad0a87d67b375ed840755e03791a6c7136c47641d94ef5cf611ab6f3e0cfc82725c872c6
7
+ data.tar.gz: 432cd9f0811511f39d4f82e4ffb074dc0511e244efb2d0575cc3f99f8945f3bc1f8a5e5a45869d72fb13704f6d05bcf0f26c4365010b3d2ca34e427f5ca3d1fb
@@ -9,8 +9,10 @@ require 'active_remote/dirty'
9
9
  require 'active_remote/dsl'
10
10
  require 'active_remote/integration'
11
11
  require 'active_remote/persistence'
12
+ require 'active_remote/primary_key'
12
13
  require 'active_remote/publication'
13
14
  require 'active_remote/rpc'
15
+ require 'active_remote/scope_keys'
14
16
  require 'active_remote/search'
15
17
  require 'active_remote/serialization'
16
18
 
@@ -26,8 +28,10 @@ module ActiveRemote
26
28
  include DSL
27
29
  include Integration
28
30
  include Persistence
31
+ include PrimaryKey
29
32
  include Publication
30
33
  include RPC
34
+ include ScopeKeys
31
35
  include Search
32
36
  include Serialization
33
37
 
@@ -32,9 +32,8 @@ module ActiveRemote
32
32
  # Tag.create_all(Generic::Remote::Tags.new(:records => [ Generic::Remote::Tag.new(:name => 'foo') ])
33
33
  #
34
34
  def create_all(*records)
35
- remote = self.new
36
- remote.execute(:create_all, parse_records(records))
37
- remote.serialize_records
35
+ response = rpc.execute(:create_all, parse_records(records))
36
+ serialize_records(response.records) if response.respond_to?(:records)
38
37
  end
39
38
 
40
39
  # Delete multiple records at the same time. Returns a collection of active
@@ -59,9 +58,8 @@ module ActiveRemote
59
58
  # Tag.delete_all(Generic::Remote::Tags.new(:records => [ Generic::Remote::Tag.new(:guid => 'foo') ])
60
59
  #
61
60
  def delete_all(*records)
62
- remote = self.new
63
- remote.execute(:delete_all, parse_records(records))
64
- remote.serialize_records
61
+ response = rpc.execute(:delete_all, parse_records(records))
62
+ serialize_records(response.records) if response.respond_to?(:records)
65
63
  end
66
64
 
67
65
  # Destroy multiple records at the same time. Returns a collection of active
@@ -86,9 +84,8 @@ module ActiveRemote
86
84
  # Tag.destroy_all(Generic::Remote::Tags.new(:records => [ Generic::Remote::Tag.new(:guid => 'foo') ])
87
85
  #
88
86
  def destroy_all(*records)
89
- remote = self.new
90
- remote.execute(:destroy_all, parse_records(records))
91
- remote.serialize_records
87
+ response = rpc.execute(:destroy_all, parse_records(records))
88
+ serialize_records(response.records) if response.respond_to?(:records)
92
89
  end
93
90
 
94
91
  # Parse given records to get them ready to be built into a request.
@@ -135,9 +132,8 @@ module ActiveRemote
135
132
  # Tag.update_all(Generic::Remote::Tags.new(:records => [ Generic::Remote::Tag.new(:guid => 'foo', :name => 'baz') ])
136
133
  #
137
134
  def update_all(*records)
138
- remote = self.new
139
- remote.execute(:update_all, parse_records(records))
140
- remote.serialize_records
135
+ response = rpc.execute(:update_all, parse_records(records))
136
+ serialize_records(response.records) if response.respond_to?(:records)
141
137
  end
142
138
  end
143
139
  end
@@ -76,7 +76,10 @@ module ActiveRemote
76
76
  #
77
77
  def delete
78
78
  raise ReadOnlyRemoteRecord if readonly?
79
- execute(:delete, "guid" => read_attribute("guid"))
79
+ response = rpc.execute(:delete, scope_key_hash)
80
+
81
+ # TODO: add errors here so success? actually does something...
82
+ # add_errors(response)
80
83
 
81
84
  return success? ? freeze : false
82
85
  end
@@ -99,7 +102,10 @@ module ActiveRemote
99
102
  #
100
103
  def destroy
101
104
  raise ReadOnlyRemoteRecord if readonly?
102
- execute(:destroy, "guid" => read_attribute("guid"))
105
+ response = execute(:destroy, scope_key_hash)
106
+
107
+ # TODO: add errors here so success? actually does something...
108
+ # add_errors(response)
103
109
 
104
110
  return success? ? freeze : false
105
111
  end
@@ -128,6 +134,10 @@ module ActiveRemote
128
134
  assign_attributes(record)
129
135
  end
130
136
 
137
+ # TODO: figure out how to safely run after_find/search callbacks here
138
+ # currently, several functions use this code path, so an alternate path
139
+ # may need to be added
140
+
131
141
  run_callbacks :initialize
132
142
 
133
143
  @new_record = false
@@ -221,12 +231,12 @@ module ActiveRemote
221
231
  run_callbacks :create do
222
232
  # Use the getter here so we get the type casting.
223
233
  new_attributes = attributes
224
- new_attributes.delete("guid")
234
+ new_attributes.delete(primary_key.to_s)
225
235
 
226
- execute(:create, new_attributes)
236
+ response = rpc.execute(:create, new_attributes)
227
237
 
228
- assign_attributes(last_response.to_hash)
229
- add_errors_from_response
238
+ assign_attributes(response.to_hash)
239
+ add_errors(response)
230
240
 
231
241
  @new_record = has_errors?
232
242
  success?
@@ -251,12 +261,12 @@ module ActiveRemote
251
261
  # Use the getter here so we get the type casting.
252
262
  updated_attributes = attributes
253
263
  updated_attributes.slice!(*attribute_names)
254
- updated_attributes.merge!("guid" => self[:guid])
264
+ updated_attributes.merge!(scope_key_hash)
255
265
 
256
- execute(:update, updated_attributes)
266
+ response = rpc.execute(:update, updated_attributes)
257
267
 
258
- assign_attributes(last_response.to_hash)
259
- add_errors_from_response
268
+ assign_attributes(response.to_hash)
269
+ add_errors(response)
260
270
 
261
271
  success?
262
272
  end
@@ -0,0 +1,37 @@
1
+ module ActiveRemote
2
+ module PrimaryKey
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ ##
8
+ # The default_primary_key is used to define what attribute is used
9
+ # as a primary key for your global code base. If you use a primary
10
+ # key other than this, you'll want to set it using the primary_key
11
+ # method listed below
12
+ #
13
+ def default_primary_key
14
+ :guid
15
+ end
16
+
17
+ ##
18
+ # In the event that you use a different primary key than the default
19
+ # primary key listed above (like :uuid, or :id), you'll use this method
20
+ # to change that primary key. This will be used when making remote
21
+ # calls to persist or refresh data.
22
+ #
23
+ def primary_key(value = nil)
24
+ @primary_key = value if value
25
+ @primary_key || default_primary_key
26
+ end
27
+ end
28
+
29
+ ##
30
+ # Instance level access to either the default primary key, or whatever
31
+ # you configured the class level primary key to be.
32
+ #
33
+ def primary_key
34
+ self.class.primary_key
35
+ end
36
+ end
37
+ end
@@ -1,3 +1,4 @@
1
+ require 'active_remote/rpc_adapters/protobuf_adapter'
1
2
  require 'active_remote/serializers/protobuf'
2
3
 
3
4
  module ActiveRemote
@@ -5,68 +6,118 @@ module ActiveRemote
5
6
  extend ActiveSupport::Concern
6
7
 
7
8
  included do
8
- include Serializers::Protobuf
9
+ include Embedded
9
10
  end
10
11
 
11
- module ClassMethods
12
+ # TODO: Deprecate this pattern of executing RPC calls
13
+ #
14
+ module Embedded
15
+ extend ActiveSupport::Concern
12
16
 
13
- # Execute an RPC call to the remote service and return the raw response.
14
- #
15
- def remote_call(rpc_method, request_args)
16
- remote = self.new
17
- remote.execute(rpc_method, request_args)
18
- remote.last_response
17
+ included do
18
+ include Serializers::Protobuf
19
19
  end
20
20
 
21
- # Return a protobuf request object for the given rpc request.
22
- #
23
- def request(rpc_method, request_args)
24
- return request_args unless request_args.is_a?(Hash)
21
+ module ClassMethods
22
+ # Return a protobuf request object for the given rpc request.
23
+ #
24
+ # TODO: Add deprecation warning
25
+ #
26
+ def request(rpc_method, request_args)
27
+ return request_args unless request_args.is_a?(Hash)
28
+
29
+ message_class = request_type(rpc_method)
30
+ fields = fields_from_attributes(message_class, request_args)
31
+ message_class.new(fields)
32
+ end
25
33
 
26
- message_class = request_type(rpc_method)
27
- fields = fields_from_attributes(message_class, request_args)
28
- message_class.new(fields)
34
+ # Return the class applicable to the request for the given rpc method.
35
+ #
36
+ # TODO: Add deprecation warning
37
+ #
38
+ def request_type(rpc_method)
39
+ service_class.rpcs[rpc_method].request_type
40
+ end
29
41
  end
30
42
 
31
- # Return the class applicable to the request for the given rpc method.
43
+ # Invoke an RPC call to the service for the given rpc method.
32
44
  #
33
- def request_type(rpc_method)
34
- service_class.rpcs[rpc_method].request_type
35
- end
36
- end
45
+ # TODO: Add deprecation warning
46
+ #
47
+ def execute(rpc_method, request_args)
48
+ @last_request = request(rpc_method, request_args)
37
49
 
38
- # Invoke an RPC call to the service for the given rpc method.
39
- #
40
- def execute(rpc_method, request_args)
41
- @last_request = request(rpc_method, request_args)
50
+ _service_class.client.__send__(rpc_method, @last_request) do |c|
42
51
 
43
- _service_class.client.__send__(rpc_method, @last_request) do |c|
52
+ # In the event of service failure, raise the error.
53
+ c.on_failure do |error|
54
+ raise ActiveRemoteError, error.message
55
+ end
44
56
 
45
- # In the event of service failure, raise the error.
46
- c.on_failure do |error|
47
- raise ActiveRemoteError, error.message
57
+ # In the event of service success, assign the response.
58
+ c.on_success do |response|
59
+ @last_response = response
60
+ end
48
61
  end
49
62
 
50
- # In the event of service success, assign the response.
51
- c.on_success do |response|
52
- @last_response = response
53
- end
63
+ @last_response
54
64
  end
55
- end
56
65
 
57
- # Execute an RPC call to the remote service and return the raw response.
58
- #
59
- def remote_call(rpc_method, request_args)
60
- self.execute(rpc_method, request_args)
61
- self.last_response
66
+
67
+ # Execute an RPC call to the remote service and return the raw response.
68
+ #
69
+ # TODO: Add deprecation warning
70
+ #
71
+ def remote_call(rpc_method, request_args)
72
+ rpc.execute(rpc_method, request_args)
73
+ end
74
+
75
+ private
76
+
77
+ # Return a protobuf request object for the given rpc call.
78
+ #
79
+ # TODO: Add deprecation warning
80
+ #
81
+ def request(rpc_method, attributes)
82
+ self.class.request(rpc_method, attributes)
83
+ end
62
84
  end
63
85
 
64
- private
86
+ module ClassMethods
65
87
 
66
- # Return a protobuf request object for the given rpc call.
67
- #
68
- def request(rpc_method, attributes)
69
- self.class.request(rpc_method, attributes)
88
+ # Execute an RPC call to the remote service and return the raw response.
89
+ #
90
+ def remote_call(rpc_method, request_args)
91
+ rpc.execute(rpc_method, request_args)
92
+ end
93
+
94
+ def rpc
95
+ @rpc ||= rpc_adapter.new(service_class)
96
+ end
97
+
98
+ def rpc_adapter
99
+ # TODO: Make this pluggable
100
+ #
101
+ # raise(AdapterNotSpecified, "configuration does not specify adapter") unless adapter.present?
102
+ #
103
+ # path_to_adapter = "active_remote/rpc_adapters/#{adapter}_adapter"
104
+ #
105
+ # begin
106
+ # require path_to_adapter
107
+ # rescue Gem::LoadError => e
108
+ # raise Gem::LoadError, "Specified '#{adapter]}' for RPC adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRemote)."
109
+ # rescue LoadError => e
110
+ # raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter is valid. If you use an adapter other than 'protobuf' add the necessary adapter gem to the Gemfile.", e.backtrace
111
+ # end
112
+ #
113
+ # path_to_adapter.classify.constantize
114
+
115
+ RPCAdapters::ProtobufAdapter
116
+ end
117
+ end
118
+
119
+ def rpc
120
+ self.class.rpc
70
121
  end
71
122
  end
72
123
  end
@@ -0,0 +1,56 @@
1
+ require 'active_remote/serializers/protobuf'
2
+
3
+ module ActiveRemote
4
+ module RPCAdapters
5
+ class ProtobufAdapter
6
+ include Serializers::Protobuf
7
+
8
+ attr_reader :last_request, :last_response, :service_class
9
+
10
+ ##
11
+ # Constructor!
12
+ #
13
+ def initialize(service_class)
14
+ @service_class = service_class
15
+ end
16
+
17
+ # Invoke an RPC call to the service for the given rpc method.
18
+ #
19
+ def execute(rpc_method, request_args)
20
+ @last_request = request(rpc_method, request_args)
21
+
22
+ service_class.client.__send__(rpc_method, @last_request) do |c|
23
+ # In the event of service failure, raise the error.
24
+ c.on_failure do |error|
25
+ raise ActiveRemoteError, error.message
26
+ end
27
+
28
+ # In the event of service success, assign the response.
29
+ c.on_success do |response|
30
+ @last_response = response
31
+ end
32
+ end
33
+
34
+ @last_response
35
+ end
36
+
37
+ private
38
+
39
+ # Return a protobuf request object for the given rpc request.
40
+ #
41
+ def request(rpc_method, request_args)
42
+ return request_args unless request_args.is_a?(Hash)
43
+
44
+ message_class = request_type(rpc_method)
45
+ fields = fields_from_attributes(message_class, request_args)
46
+ message_class.new(fields)
47
+ end
48
+
49
+ # Return the class applicable to the request for the given rpc method.
50
+ #
51
+ def request_type(rpc_method)
52
+ service_class.rpcs[rpc_method].request_type
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,66 @@
1
+ module ActiveRemote
2
+ module ScopeKeys
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include PrimaryKey
7
+
8
+ class_attribute :_scope_keys
9
+ self._scope_keys = []
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ ##
15
+ # Allows you to define, at a class level, what keys should be
16
+ # used as identifiers when making remote calls. For instance,
17
+ #
18
+ # class Tag < ActiveRemote::Base
19
+ # scope_key :user_guid
20
+ # end
21
+ #
22
+ # When #scope_keys is called on Tag, it will return the primary
23
+ # key in addition to :user_guid as the scope keys.
24
+ #
25
+ def scope_key(*keys)
26
+ self._scope_keys += keys.map(&:to_s)
27
+ end
28
+
29
+ ##
30
+ # Used to define what keys are required when making remote
31
+ # persistence or refresh calls.
32
+ #
33
+ def scope_keys
34
+ [ primary_key.to_s ] + _scope_keys
35
+ end
36
+ end
37
+
38
+ ##
39
+ # Instance level access to the scope key of the current class
40
+ #
41
+ def scope_keys
42
+ @scope_keys ||= self.class.scope_keys
43
+ end
44
+
45
+ ##
46
+ # Instance level hash of scope keys and their corresponding
47
+ # values. For instance,
48
+ #
49
+ # class Tag < ActiveRemote::Base
50
+ # scope_key :user_guid
51
+ # end
52
+ #
53
+ # would return this hash:
54
+ #
55
+ # {
56
+ # :guid => tag[:guid],
57
+ # :user_guid => tag[:user_guid]
58
+ # }
59
+ #
60
+ # This hash is used when accessing or modifying a remote object
61
+ # like when calling #update in the persistence module, for example.
62
+ def scope_key_hash
63
+ attributes.slice(*scope_keys)
64
+ end
65
+ end
66
+ end
@@ -91,9 +91,12 @@ module ActiveRemote
91
91
  def search(args)
92
92
  args = _active_remote_search_args(args)
93
93
 
94
- remote = self.new
95
- remote._active_remote_search(args)
96
- remote.serialize_records
94
+ response = rpc.execute(:search, args)
95
+
96
+ if response.respond_to?(:records)
97
+ records = serialize_records(response.records)
98
+ records.each { |record| record.run_callbacks :search }
99
+ end
97
100
  end
98
101
 
99
102
  # :noapi:
@@ -116,16 +119,16 @@ module ActiveRemote
116
119
  #
117
120
  def _active_remote_search(args)
118
121
  run_callbacks :search do
119
- execute(:search, args)
122
+ rpc.execute(:search, args)
120
123
  end
121
124
  end
122
125
 
123
126
  # Reload this record from the remote service.
124
127
  #
125
128
  def reload
126
- _active_remote_search(:guid => self.guid)
129
+ response = self.class.find(scope_key_hash)
127
130
 
128
- fresh_object = self.class.new(last_response.to_hash)
131
+ fresh_object = self.class.instantiate(response.to_hash)
129
132
  @attributes.update(fresh_object.instance_variable_get('@attributes'))
130
133
  end
131
134
  end
@@ -8,34 +8,60 @@ module ActiveRemote
8
8
  include Serializers::JSON
9
9
  end
10
10
 
11
+ module ClassMethods
12
+ # Serialize the given records into Active Remote objects.
13
+ #
14
+ # ====Examples
15
+ #
16
+ # records = [ Generic::Remote::TagRequest.new(:name => 'foo') ]
17
+ #
18
+ # Tag.serialize_records(records) # => [ Tag#{:name => 'foo'} ]
19
+ #
20
+ def serialize_records(records)
21
+ records.map { |record| instantiate(record.to_hash) }
22
+ end
23
+ end
24
+
11
25
  # Examine the given response and add any errors to our internal errors
12
- # list. If no response is given, use the last response.
26
+ # list.
13
27
  #
14
- def add_errors_from_response(response=self.last_response)
15
- return unless response.respond_to?(:errors)
16
-
17
- response.errors.each do |error|
28
+ # ====Examples
29
+ #
30
+ # response = remote_call(:action_that_returns_errors, { :stuff => 'foo' })
31
+ #
32
+ # add_errors(response.errors)
33
+ #
34
+ def add_errors(errors)
35
+ errors.each do |error|
18
36
  if error.respond_to?(:message)
19
- errors.add(error.field, error.message)
37
+ self.errors.add(error.field, error.message)
20
38
  elsif error.respond_to?(:messages)
21
39
  error.messages.each do |message|
22
- errors.add(error.field, message)
40
+ self.errors.add(error.field, message)
23
41
  end
24
42
  end
25
43
  end
26
44
  end
27
45
 
28
- # Examine the last response and serialize any records returned into Active
29
- # Remote objects.
46
+ # DEPRECATED Use :add_errors instead
30
47
  #
31
- def serialize_records
32
- return nil unless last_response.respond_to?(:records)
48
+ def add_errors_from_response(response = nil)
49
+ warn 'DEPRECATED :add_errors_from_response is deprecated and will be removed in Active Remote 3.0. Use :add_errors instead'
33
50
 
34
- last_response.records.map do |remote_record|
35
- record = self.class.allocate
36
- record.instantiate(remote_record.to_hash)
37
- record
38
- end
51
+ response ||= last_response
52
+
53
+ add_errors(response.errors) if response.respond_to?(:errors)
54
+ end
55
+
56
+ # DEPRECATED – Use the class-level :serialize_errors instead
57
+ #
58
+ def serialize_records(records = nil)
59
+ warn 'DEPRECATED Calling :serialize_records on an instance is deprecated and will be removed in Active Remote 3.0. Use the class-level :serialize_records instead'
60
+
61
+ records ||= last_response.records if last_response.respond_to?(:records)
62
+ return if records.nil?
63
+
64
+ self.class.serialize_records(records)
39
65
  end
40
66
  end
41
67
  end
@@ -5,7 +5,7 @@ module ActiveRemote
5
5
  #
6
6
  def as_json(options = {})
7
7
  options ||= {}
8
-
8
+
9
9
  default_options = { :only => _publishable_json_attributes, :methods => _publishable_json_methods }
10
10
  default_options.merge!(options)
11
11
 
@@ -1,3 +1,3 @@
1
1
  module ActiveRemote
2
- VERSION = "2.0.2"
2
+ VERSION = "2.1.0.beta1"
3
3
  end
@@ -5,37 +5,28 @@ describe ActiveRemote::Bulk do
5
5
  let(:serialized_records) { double(:serialized_records) }
6
6
 
7
7
  describe ".create_all" do
8
- before {
9
- Tag.stub(:parse_records).and_return(records)
10
- Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
11
- }
8
+ before { Tag.better_stub(:parse_records).and_return(records) }
12
9
 
13
10
  it "creates remote records" do
14
- Tag.any_instance.should_receive(:execute).with(:create_all, records)
11
+ Tag.rpc.better_receive(:execute).with(:create_all, records)
15
12
  Tag.create_all(records)
16
13
  end
17
14
  end
18
15
 
19
16
  describe ".delete_all" do
20
- before {
21
- Tag.stub(:parse_records).and_return(records)
22
- Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
23
- }
17
+ before { Tag.better_stub(:parse_records).and_return(records) }
24
18
 
25
19
  it "deletes remote records" do
26
- Tag.any_instance.should_receive(:execute).with(:delete_all, records)
20
+ Tag.rpc.better_receive(:execute).with(:delete_all, records)
27
21
  Tag.delete_all(records)
28
22
  end
29
23
  end
30
24
 
31
25
  describe ".destroy_all" do
32
- before {
33
- Tag.stub(:parse_records).and_return(records)
34
- Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
35
- }
26
+ before { Tag.better_stub(:parse_records).and_return(records) }
36
27
 
37
28
  it "destroys remote records" do
38
- Tag.any_instance.should_receive(:execute).with(:destroy_all, records)
29
+ Tag.rpc.better_receive(:execute).with(:destroy_all, records)
39
30
  Tag.destroy_all(records)
40
31
  end
41
32
  end
@@ -78,13 +69,10 @@ describe ActiveRemote::Bulk do
78
69
  end
79
70
 
80
71
  describe ".update_all" do
81
- before {
82
- Tag.stub(:parse_records).and_return(records)
83
- Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
84
- }
72
+ before { Tag.stub(:parse_records).and_return(records) }
85
73
 
86
74
  it "updates remote records" do
87
- Tag.any_instance.should_receive(:execute).with(:update_all, records)
75
+ Tag.rpc.better_receive(:execute).with(:update_all, records)
88
76
  Tag.update_all(records)
89
77
  end
90
78
  end
@@ -47,8 +47,7 @@ describe ActiveRemote::Dirty do
47
47
  subject { Post.new(:name => 'foo') }
48
48
 
49
49
  before {
50
- subject.stub(:last_response).and_return({})
51
- subject.stub(:execute)
50
+ Post.stub(:find).and_return({})
52
51
  subject.reload
53
52
  }
54
53
 
@@ -83,23 +82,18 @@ describe ActiveRemote::Dirty do
83
82
  its(:changes) { should be_empty }
84
83
  end
85
84
 
86
- describe "#serialize_records" do
85
+ describe "#instantiate" do
87
86
  let(:post) { Post.new }
88
87
  let(:record) { ::Generic::Remote::Post.new(:name => 'foo') }
89
- let(:response) { double(:response, :records => [ record ]) }
90
-
91
- before {
92
- post.stub(:last_response).and_return(response)
93
- }
94
88
 
95
89
  it "clears previous changes" do
96
- records = post.serialize_records
97
- records.first.previous_changes.should be_nil
90
+ new_record = post.instantiate(record.to_hash)
91
+ new_record.previous_changes.should be_nil
98
92
  end
99
93
 
100
94
  it "clears changes" do
101
- records = post.serialize_records
102
- records.first.changes.should be_empty
95
+ new_record = post.instantiate(record.to_hash)
96
+ new_record.changes.should be_empty
103
97
  end
104
98
  end
105
99
  end
@@ -1,20 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveRemote::Persistence do
4
+ let(:rpc) { Tag.new }
5
+
4
6
  subject { Tag.new }
5
7
 
6
- before { Tag.any_instance.stub(:last_response).and_return(HashWithIndifferentAccess.new) }
8
+ before {
9
+ rpc.better_stub(:execute).and_return(HashWithIndifferentAccess.new)
10
+ Tag.better_stub(:rpc).and_return(rpc)
11
+ }
12
+ after { Tag.unstub(:rpc) }
7
13
 
8
14
  describe ".create" do
9
- before { Tag.any_instance.stub(:execute) }
10
- after { Tag.any_instance.unstub(:execute) }
11
-
12
15
  it "runs create callbacks" do
13
16
  Tag.any_instance.should_receive(:after_create_callback)
14
17
  Tag.create(:name => 'foo')
15
18
  end
16
19
 
17
-
18
20
  it "initializes and saves a new record" do
19
21
  Tag.any_instance.should_receive(:save)
20
22
  Tag.create(:name => 'foo')
@@ -27,9 +29,6 @@ describe ActiveRemote::Persistence do
27
29
  end
28
30
 
29
31
  describe ".create!" do
30
- before { Tag.any_instance.stub(:execute) }
31
- after { Tag.any_instance.unstub(:execute) }
32
-
33
32
  it "initializes and saves a new record" do
34
33
  Tag.any_instance.should_receive(:save!)
35
34
  Tag.create!(:name => 'foo')
@@ -45,11 +44,8 @@ describe ActiveRemote::Persistence do
45
44
  end
46
45
 
47
46
  describe "#delete" do
48
- before { subject.stub(:execute) }
49
- after { subject.unstub(:execute) }
50
-
51
47
  it "deletes a remote record" do
52
- subject.should_receive(:execute).with(:delete, subject.attributes.slice("guid"))
48
+ rpc.should_receive(:execute).with(:delete, subject.scope_key_hash)
53
49
  subject.delete
54
50
  end
55
51
 
@@ -60,31 +56,35 @@ describe ActiveRemote::Persistence do
60
56
  end
61
57
  end
62
58
 
63
- context "when the record has errors" do
64
- before { subject.stub(:has_errors?).and_return(true) }
65
-
66
- it "returns false" do
67
- subject.delete.should be_false
68
- end
69
- end
59
+ # TODO: This spec passes, but the implementation does not actually work.
60
+ # Uncomment it once the implementation is correct.
61
+ #
62
+ # context "when the record has errors" do
63
+ # before { subject.stub(:has_errors?).and_return(true) }
64
+ #
65
+ # it "returns false" do
66
+ # subject.delete.should be_false
67
+ # end
68
+ # end
70
69
  end
71
70
 
72
71
  describe "#delete!" do
73
- before { subject.stub(:execute) }
74
- after { subject.unstub(:execute) }
75
-
76
72
  it "deletes a remote record" do
77
- subject.should_receive(:execute).with(:delete, subject.attributes.slice("guid"))
73
+ rpc.should_receive(:execute).with(:delete, subject.scope_key_hash)
78
74
  subject.delete!
79
75
  end
80
76
 
81
- context "when an error occurs" do
82
- before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
83
-
84
- it "raises an exception" do
85
- expect { subject.delete! }.to raise_error(ActiveRemote::ActiveRemoteError)
86
- end
87
- end
77
+ # FIXME: This spec tests that excute raises an execption, not that an
78
+ # exception is raised when an error is returned (as it should).
79
+ # Uncomment it once the implementation is correct.
80
+ #
81
+ # context "when an error occurs" do
82
+ # before { rpc.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
83
+ #
84
+ # it "raises an exception" do
85
+ # expect { subject.delete! }.to raise_error(ActiveRemote::ActiveRemoteError)
86
+ # end
87
+ # end
88
88
  end
89
89
 
90
90
  describe "#destroy" do
@@ -92,7 +92,7 @@ describe ActiveRemote::Persistence do
92
92
  after { subject.unstub(:execute) }
93
93
 
94
94
  it "destroys a remote record" do
95
- subject.should_receive(:execute).with(:destroy, subject.attributes.slice("guid"))
95
+ subject.should_receive(:execute).with(:destroy, subject.scope_key_hash)
96
96
  subject.destroy
97
97
  end
98
98
 
@@ -103,31 +103,35 @@ describe ActiveRemote::Persistence do
103
103
  end
104
104
  end
105
105
 
106
- context "when the record has errors" do
107
- before { subject.stub(:has_errors?).and_return(true) }
108
-
109
- it "returns false" do
110
- subject.destroy.should be_false
111
- end
112
- end
106
+ # TODO: This spec passes, but the implementation does not actually work.
107
+ # Uncomment it once the implementation is correct.
108
+ #
109
+ # context "when the record has errors" do
110
+ # before { subject.stub(:has_errors?).and_return(true) }
111
+ #
112
+ # it "returns false" do
113
+ # subject.destroy.should be_false
114
+ # end
115
+ # end
113
116
  end
114
117
 
115
118
  describe "#destroy!" do
116
- before { subject.stub(:execute) }
117
- after { subject.unstub(:execute) }
118
-
119
119
  it "destroys a remote record" do
120
120
  subject.should_receive(:execute).with(:destroy, subject.attributes.slice("guid"))
121
121
  subject.destroy!
122
122
  end
123
123
 
124
- context "when an error occurs" do
125
- before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
126
-
127
- it "raises an exception" do
128
- expect { subject.destroy! }.to raise_error(ActiveRemote::ActiveRemoteError)
129
- end
130
- end
124
+ # FIXME: This spec tests that excute raises an execption, not that an
125
+ # exception is raised when an error is returned (as it should).
126
+ # Uncomment it once the implementation is correct.
127
+ #
128
+ # context "when an error occurs" do
129
+ # before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
130
+ #
131
+ # it "raises an exception" do
132
+ # expect { subject.destroy! }.to raise_error(ActiveRemote::ActiveRemoteError)
133
+ # end
134
+ # end
131
135
  end
132
136
 
133
137
  describe "#readonly?" do
@@ -188,9 +192,6 @@ describe ActiveRemote::Persistence do
188
192
  end
189
193
 
190
194
  describe "#save" do
191
- before { subject.stub(:execute) }
192
- after { subject.unstub(:execute) }
193
-
194
195
  it "runs save callbacks" do
195
196
  subject.should_receive(:run_callbacks).with(:save)
196
197
  subject.save
@@ -201,7 +202,7 @@ describe ActiveRemote::Persistence do
201
202
 
202
203
  it "creates the record" do
203
204
  expected_attributes = subject.attributes.reject { |key, value| key == "guid" }
204
- subject.should_receive(:execute).with(:create, expected_attributes)
205
+ rpc.should_receive(:execute).with(:create, expected_attributes)
205
206
  subject.save
206
207
  end
207
208
  end
@@ -212,7 +213,7 @@ describe ActiveRemote::Persistence do
212
213
  subject { Tag.allocate.instantiate(attributes) }
213
214
 
214
215
  it "updates the record" do
215
- subject.should_receive(:execute).with(:update, attributes)
216
+ rpc.should_receive(:execute).with(:update, attributes)
216
217
  subject.save
217
218
  end
218
219
  end
@@ -277,16 +278,21 @@ describe ActiveRemote::Persistence do
277
278
 
278
279
  describe "#update_attributes" do
279
280
  let(:attributes) { HashWithIndifferentAccess.new(:name => 'bar') }
281
+ let(:tag) { Tag.allocate.instantiate({:guid => "123"}) }
280
282
 
281
- before { Tag.any_instance.stub(:execute) }
282
- after { Tag.any_instance.unstub(:execute) }
283
+ before { Tag.rpc.stub(:execute).and_return(HashWithIndifferentAccess.new) }
284
+ after { Tag.rpc.unstub(:execute) }
283
285
 
284
286
  it "runs update callbacks" do
285
- tag = Tag.allocate.instantiate({:guid => "123"})
286
287
  tag.should_receive(:after_update_callback)
287
288
  tag.update_attributes({})
288
289
  end
289
290
 
291
+ it "updates a remote record" do
292
+ Tag.rpc.should_receive(:execute).with(:update, tag.scope_key_hash)
293
+ tag.update_attributes({})
294
+ end
295
+
290
296
  before { subject.stub(:save) }
291
297
  after { subject.unstub(:save) }
292
298
 
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::PrimaryKey do
4
+ let(:tag) { Tag.new(:id => '1234', :guid => 'TAG-123', :user_guid => 'USR-123') }
5
+
6
+ after { Tag.instance_variable_set :@primary_key, nil }
7
+
8
+ describe ".default_primary_key" do
9
+ it 'returns array of :guid' do
10
+ Tag.default_primary_key.should eq(:guid)
11
+ end
12
+ end
13
+
14
+ describe "primary_key" do
15
+ context "when no arguments are passed" do
16
+ it "returns default primary key" do
17
+ Tag.primary_key.should eq(:guid)
18
+ end
19
+ end
20
+
21
+ context "when arguments are passed" do
22
+ let(:specified_primary_key) { :name }
23
+
24
+ it "returns the given primary key" do
25
+ Tag.primary_key(specified_primary_key).should eq(specified_primary_key)
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "#primary_key" do
31
+ it "returns the primary key for the class" do
32
+ Tag.new.primary_key.should eq Tag.primary_key
33
+ end
34
+ end
35
+ end
@@ -7,15 +7,15 @@ describe ActiveRemote::RPC do
7
7
  let(:args) { double(:args) }
8
8
  let(:response) { double(:response) }
9
9
 
10
- before { Tag.any_instance.stub(:execute) }
10
+ before { Tag.rpc.stub(:execute) }
11
11
 
12
12
  it "calls the given RPC method" do
13
- Tag.any_instance.should_receive(:execute).with(:remote_method, args)
13
+ Tag.rpc.should_receive(:execute).with(:remote_method, args)
14
14
  Tag.remote_call(:remote_method, args)
15
15
  end
16
16
 
17
17
  it "returns the response" do
18
- Tag.any_instance.stub(:last_response).and_return(response)
18
+ Tag.rpc.stub(:execute).and_return(response)
19
19
  Tag.remote_call(:remote_method, args).should eq response
20
20
  end
21
21
  end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::ScopeKeys do
4
+ let(:key) { :user_guid }
5
+ let(:_scope_keys) { [ 'user_guid' ] }
6
+ let(:scope_keys) { [ 'guid' ] + _scope_keys }
7
+ let(:tag) { Tag.new(tag_hash) }
8
+ let(:tag_hash) { { :guid => 'TAG-123', :user_guid => 'USR-123', :name => 'teh tag' } }
9
+
10
+ describe ".scope_key" do
11
+ after { Tag._scope_keys = [] }
12
+
13
+ it 'adds scope_key to _scope_keys' do
14
+ Tag.scope_key(key)
15
+ Tag._scope_keys.should eq(_scope_keys)
16
+ end
17
+ end
18
+
19
+ describe ".scope_keys" do
20
+ before { Tag.better_stub(:_scope_keys).and_return(_scope_keys) }
21
+
22
+ it "combines primary key with _scope_keys" do
23
+ Tag.scope_keys.should eq(['guid'] + _scope_keys)
24
+ end
25
+ end
26
+
27
+ describe "#scope_keys" do
28
+ it "returns the scope keys for the class" do
29
+ Tag.new.scope_keys.should eq Tag.scope_keys
30
+ end
31
+ end
32
+
33
+ describe "#scope_key_hash" do
34
+ let(:scope_key_hash) { { 'guid' => 'TAG-123', 'user_guid' => 'USR-123' } }
35
+
36
+ before { tag.better_stub(:scope_keys).and_return(scope_keys) }
37
+
38
+ it "returns a attribute hash of scope_keys" do
39
+ tag.scope_key_hash.should eq(scope_key_hash)
40
+ end
41
+ end
42
+ end
@@ -1,6 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveRemote::Search do
4
+ let(:records) { [ Generic::Remote::Tag.new ] }
5
+ let(:response) { Generic::Remote::Tags.new(:records => records) }
6
+ let(:rpc) { double(:rpc) }
7
+
4
8
  describe ".find" do
5
9
  let(:args) { Hash.new }
6
10
  let(:record) { double(:record) }
@@ -33,23 +37,20 @@ describe ActiveRemote::Search do
33
37
  end
34
38
 
35
39
  describe ".search" do
40
+ let(:serialized_records) { [ Tag.new ] }
41
+
36
42
  context "given args that respond to :to_hash" do
37
43
  let(:args) { Hash.new }
38
44
 
39
- before {
40
- Tag.any_instance.stub(:_active_remote_search)
41
- }
45
+ before { Tag.rpc.stub(:execute).and_return(response) }
42
46
 
43
47
  it "searches with the given args" do
44
- Tag.any_instance.should_receive(:_active_remote_search).with(args)
48
+ Tag.rpc.should_receive(:execute).with(:search, args)
45
49
  Tag.search(args)
46
50
  end
47
51
 
48
52
  it "returns records" do
49
- records = double(:records)
50
-
51
- Tag.any_instance.stub(:serialize_records).and_return(records)
52
- Tag.search(args).should eq records
53
+ Tag.search(args).should eq serialized_records
53
54
  end
54
55
  end
55
56
 
@@ -67,30 +68,32 @@ describe ActiveRemote::Search do
67
68
 
68
69
  subject { Tag.new }
69
70
 
71
+ before {
72
+ rpc.stub(:execute).and_return(response)
73
+ Tag.better_stub(:rpc).and_return(rpc)
74
+ }
75
+
70
76
  it "runs callbacks" do
71
77
  subject.should_receive(:run_callbacks).with(:search)
72
78
  subject._active_remote_search(args)
73
79
  end
74
80
 
75
81
  it "executes the search" do
76
- subject.should_receive(:execute).with(:search, args)
82
+ rpc.should_receive(:execute).with(:search, args)
77
83
  subject._active_remote_search(args)
78
84
  end
79
85
  end
80
86
 
81
87
  describe "#reload" do
82
- let(:args) { { :guid => 'foo' } }
83
- let(:attributes) { HashWithIndifferentAccess.new(:guid => 'foo', :name => 'bar', :updated_at => nil) }
88
+ let(:args) { attributes.slice('guid', 'user_guid') }
89
+ let(:attributes) { HashWithIndifferentAccess.new(:guid => 'foo', :name => 'bar', :updated_at => nil, :user_guid => 'baz') }
84
90
 
85
91
  subject { Tag.new(args) }
86
92
 
87
- before {
88
- subject.stub(:_active_remote_search)
89
- subject.stub(:last_response).and_return(attributes)
90
- }
93
+ before { Tag.better_stub(:find).and_return(attributes) }
91
94
 
92
95
  it "reloads the record" do
93
- subject.should_receive(:_active_remote_search).with(args)
96
+ Tag.better_receive(:find).with(subject.scope_key_hash)
94
97
  subject.reload
95
98
  end
96
99
 
@@ -1,64 +1,32 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveRemote::Serialization do
4
- describe "#add_errors_from_response" do
5
- let(:error) { Generic::Error.new(:field => 'name', :message => 'Boom!') }
6
- let(:response) {
7
- tag = Generic::Remote::Tag.new
8
- tag.errors << error
9
- tag
10
- }
4
+ describe ".serialize_records" do
5
+ let(:records) { [ { :foo => 'bar' } ] }
11
6
 
12
7
  subject { Tag.new }
13
8
 
14
- context "when the response has errors" do
15
- it "adds the errors to the active remote object" do
16
- subject.add_errors_from_response(response)
17
- subject.errors[:name].should =~ ['Boom!']
18
- end
19
- end
20
-
21
- context "when the response doesn't respond to errors" do
22
- let(:response) { Generic::Remote::Tag.new }
23
-
24
- it "doesn't add errors" do
25
- subject.add_errors_from_response(response)
26
- subject.errors.empty?.should be_true
27
- end
28
- end
29
-
30
- context "when no response is given" do
31
- before { subject.stub(:last_response).and_return(response) }
32
-
33
- it "uses the last response" do
34
- subject.add_errors_from_response
35
- subject.errors[:name].should =~ ['Boom!']
9
+ it "serializes records into active remote objects" do
10
+ Tag.serialize_records(records).each do |record|
11
+ record.should be_a Tag
36
12
  end
37
13
  end
38
14
  end
39
15
 
40
- describe "#serialize_records" do
41
- let(:last_response) {
42
- MessageWithOptions.new(:records => records)
16
+ describe "#add_errors" do
17
+ let(:error) { Generic::Error.new(:field => 'name', :message => 'Boom!') }
18
+ let(:response) {
19
+ tag = Generic::Remote::Tag.new
20
+ tag.errors << error
21
+ tag
43
22
  }
44
- let(:records) { [ { :foo => 'bar' } ] }
45
23
 
46
24
  subject { Tag.new }
47
25
 
48
- context "when the last response has records" do
49
-
50
- before { subject.stub(:last_response).and_return(last_response) }
51
-
52
- it "serializes records into active remote objects" do
53
- subject.serialize_records.each do |record|
54
- record.should be_a Tag
55
- end
56
- end
57
- end
58
-
59
- context "when the last response doesn't respond to records" do
60
- it "returns nil" do
61
- subject.serialize_records.should be_nil
26
+ context "when the response has errors" do
27
+ it "adds the errors to the active remote object" do
28
+ subject.add_errors(response.errors)
29
+ subject.errors[:name].should =~ ['Boom!']
62
30
  end
63
31
  end
64
32
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe ActiveRemote::Serializers::JSON do
4
4
  describe "#as_json" do
5
- let(:attributes) { { :guid => 'foo', :name => 'bar', :updated_at => nil } }
5
+ let(:attributes) { { :guid => 'foo', :name => 'bar', :updated_at => nil, :user_guid => 'baz' } }
6
6
  let(:serializable_attributes) { { "tag" => attributes.stringify_keys } }
7
7
 
8
8
  subject { Tag.new(attributes) }
@@ -9,6 +9,7 @@ class Tag < ::ActiveRemote::Base
9
9
  attribute :guid
10
10
  attribute :name
11
11
  attribute :updated_at
12
+ attribute :user_guid
12
13
 
13
14
  after_update :after_update_callback
14
15
  after_create :after_create_callback
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hutchison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-08 00:00:00.000000000 Z
11
+ date: 2014-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_attr
@@ -181,9 +181,12 @@ files:
181
181
  - lib/active_remote/errors.rb
182
182
  - lib/active_remote/integration.rb
183
183
  - lib/active_remote/persistence.rb
184
+ - lib/active_remote/primary_key.rb
184
185
  - lib/active_remote/publication.rb
185
186
  - lib/active_remote/railtie.rb
186
187
  - lib/active_remote/rpc.rb
188
+ - lib/active_remote/rpc_adapters/protobuf_adapter.rb
189
+ - lib/active_remote/scope_keys.rb
187
190
  - lib/active_remote/search.rb
188
191
  - lib/active_remote/serialization.rb
189
192
  - lib/active_remote/serializers/json.rb
@@ -197,8 +200,10 @@ files:
197
200
  - spec/lib/active_remote/dsl_spec.rb
198
201
  - spec/lib/active_remote/integration_spec.rb
199
202
  - spec/lib/active_remote/persistence_spec.rb
203
+ - spec/lib/active_remote/primary_key_spec.rb
200
204
  - spec/lib/active_remote/publication_spec.rb
201
205
  - spec/lib/active_remote/rpc_spec.rb
206
+ - spec/lib/active_remote/scope_keys_spec.rb
202
207
  - spec/lib/active_remote/search_spec.rb
203
208
  - spec/lib/active_remote/serialization_spec.rb
204
209
  - spec/lib/active_remote/serializers/json_spec.rb
@@ -238,9 +243,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
238
243
  version: '0'
239
244
  required_rubygems_version: !ruby/object:Gem::Requirement
240
245
  requirements:
241
- - - ">="
246
+ - - ">"
242
247
  - !ruby/object:Gem::Version
243
- version: '0'
248
+ version: 1.3.1
244
249
  requirements: []
245
250
  rubyforge_project:
246
251
  rubygems_version: 2.2.1
@@ -256,8 +261,10 @@ test_files:
256
261
  - spec/lib/active_remote/dsl_spec.rb
257
262
  - spec/lib/active_remote/integration_spec.rb
258
263
  - spec/lib/active_remote/persistence_spec.rb
264
+ - spec/lib/active_remote/primary_key_spec.rb
259
265
  - spec/lib/active_remote/publication_spec.rb
260
266
  - spec/lib/active_remote/rpc_spec.rb
267
+ - spec/lib/active_remote/scope_keys_spec.rb
261
268
  - spec/lib/active_remote/search_spec.rb
262
269
  - spec/lib/active_remote/serialization_spec.rb
263
270
  - spec/lib/active_remote/serializers/json_spec.rb