active_remote 1.8.1 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Rakefile +3 -3
- data/active_remote.gemspec +3 -3
- data/lib/active_remote/association.rb +1 -7
- data/lib/active_remote/attributes.rb +2 -2
- data/lib/active_remote/base.rb +17 -14
- data/lib/active_remote/bulk.rb +5 -9
- data/lib/active_remote/config.rb +1 -3
- data/lib/active_remote/core_ext.rb +3 -0
- data/lib/active_remote/dirty.rb +5 -5
- data/lib/active_remote/dsl.rb +12 -20
- data/lib/active_remote/errors.rb +0 -3
- data/lib/active_remote/integration.rb +10 -11
- data/lib/active_remote/persistence.rb +174 -184
- data/lib/active_remote/railtie.rb +2 -2
- data/lib/active_remote/rpc.rb +3 -10
- data/lib/active_remote/search.rb +6 -7
- data/lib/active_remote/serialization.rb +4 -4
- data/lib/active_remote/version.rb +1 -1
- data/lib/active_remote.rb +3 -11
- data/spec/core_ext/date_time_spec.rb +1 -2
- data/spec/lib/active_remote/rpc_spec.rb +1 -3
- data/spec/support/definitions/support/protobuf/category.proto +3 -3
- data/spec/support/protobuf/author.pb.rb +5 -5
- data/spec/support/protobuf/post.pb.rb +8 -8
- data/spec/support/protobuf/tag.pb.rb +4 -4
- metadata +11 -13
- data/lib/active_remote/serializers/protobuf.rb +0 -98
- data/spec/lib/active_remote/serializers/protobuf_spec.rb +0 -95
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dc9d2dd1642d99e8a275ab2abf1b7f0690c6589
|
4
|
+
data.tar.gz: 820834a78deb45faf1d0a3e2ec3a1b12610a8334
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 820a8bb3f47437f9ed7b623317392f9ccf6b1116d1d8f26f3fd2972fc6074ae7a5f771743196425a07c4862c0db5fa164beeb1e3173f9d63708b0ac7d7ce0ed8
|
7
|
+
data.tar.gz: e4b17125fc1a49634bb4985112c7f76edb9e5caac9df18eefb5471a81cf18248f9c96244c0f6ace2a27b0a4f74ff7df61f056ff1edce7698fc5198cfbec1df7d
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -9,13 +9,13 @@ desc "Run specs (default)"
|
|
9
9
|
task :default, [] => :spec
|
10
10
|
|
11
11
|
desc "Remove protobuf definitions that have been compiled"
|
12
|
-
task :clean do
|
12
|
+
task :clean do
|
13
13
|
FileUtils.rm(Dir.glob("spec/support/protobuf/**/*.proto"))
|
14
14
|
puts "Cleaned"
|
15
15
|
end
|
16
16
|
|
17
17
|
desc "Compile spec/support protobuf definitions"
|
18
|
-
task :compile, [] => :clean do
|
19
|
-
cmd = "
|
18
|
+
task :compile, [] => :clean do
|
19
|
+
cmd = "protoc --ruby_out=spec/support/protobuf --proto_path=spec/support/definitions spec/support/definitions/*.proto"
|
20
20
|
sh(cmd)
|
21
21
|
end
|
data/active_remote.gemspec
CHANGED
@@ -19,9 +19,9 @@ Gem::Specification.new do |s|
|
|
19
19
|
##
|
20
20
|
# Dependencies
|
21
21
|
#
|
22
|
-
s.add_dependency "active_attr"
|
23
|
-
s.add_dependency "activesupport"
|
24
|
-
s.add_dependency "protobuf", ">=
|
22
|
+
s.add_dependency "active_attr", ">= 0.8"
|
23
|
+
s.add_dependency "activesupport", ">= 3.2"
|
24
|
+
s.add_dependency "protobuf", ">= 3.0.0.alpha"
|
25
25
|
|
26
26
|
##
|
27
27
|
# Development Dependencies
|
@@ -1,10 +1,6 @@
|
|
1
1
|
module ActiveRemote
|
2
2
|
module Association
|
3
|
-
|
4
|
-
klass.class_eval do
|
5
|
-
extend ::ActiveRemote::Association::ClassMethods
|
6
|
-
end
|
7
|
-
end
|
3
|
+
extend ActiveSupport::Concern
|
8
4
|
|
9
5
|
module ClassMethods
|
10
6
|
# Create a `belongs_to` association for a given remote resource.
|
@@ -137,7 +133,6 @@ module ActiveRemote
|
|
137
133
|
private
|
138
134
|
|
139
135
|
def perform_association(associated_klass, options={})
|
140
|
-
|
141
136
|
define_method(associated_klass) do
|
142
137
|
klass_name = options.fetch(:class_name){ associated_klass }
|
143
138
|
klass = klass_name.to_s.classify.constantize
|
@@ -154,7 +149,6 @@ module ActiveRemote
|
|
154
149
|
return value
|
155
150
|
end
|
156
151
|
end
|
157
|
-
|
158
152
|
end
|
159
153
|
end
|
160
154
|
end
|
@@ -8,7 +8,7 @@ module ActiveRemote
|
|
8
8
|
if respond_to? name
|
9
9
|
attribute(name)
|
10
10
|
else
|
11
|
-
raise
|
11
|
+
raise ActiveAttr::UnknownAttributeError, "unknown attribute: #{name}"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
alias_method :[], :read_attribute
|
@@ -21,7 +21,7 @@ module ActiveRemote
|
|
21
21
|
if respond_to? "#{name}="
|
22
22
|
__send__("attribute=", name, value)
|
23
23
|
else
|
24
|
-
raise
|
24
|
+
raise ActiveAttr::UnknownAttributeError, "unknown attribute: #{name}"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
alias_method :[]=, :write_attribute
|
data/lib/active_remote/base.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'active_model/callbacks'
|
2
|
+
require 'active_attr/model'
|
3
|
+
|
1
4
|
require 'active_remote/association'
|
2
5
|
require 'active_remote/attributes'
|
3
6
|
require 'active_remote/bulk'
|
@@ -13,24 +16,24 @@ require 'active_remote/serialization'
|
|
13
16
|
|
14
17
|
module ActiveRemote
|
15
18
|
class Base
|
16
|
-
extend
|
19
|
+
extend ActiveModel::Callbacks
|
17
20
|
|
18
|
-
include
|
21
|
+
include ActiveAttr::Model
|
19
22
|
|
20
|
-
include
|
21
|
-
include
|
22
|
-
include
|
23
|
-
include
|
24
|
-
include
|
25
|
-
include
|
26
|
-
include
|
27
|
-
include
|
28
|
-
include
|
29
|
-
include
|
23
|
+
include Association
|
24
|
+
include Attributes
|
25
|
+
include Bulk
|
26
|
+
include DSL
|
27
|
+
include Integration
|
28
|
+
include Persistence
|
29
|
+
include Publication
|
30
|
+
include RPC
|
31
|
+
include Search
|
32
|
+
include Serialization
|
30
33
|
|
31
34
|
# Overrides some methods, providing support for dirty tracking,
|
32
35
|
# so it needs to be included last.
|
33
|
-
include
|
36
|
+
include Dirty
|
34
37
|
|
35
38
|
attr_reader :last_request, :last_response
|
36
39
|
|
@@ -56,5 +59,5 @@ module ActiveRemote
|
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
59
|
-
|
62
|
+
ActiveSupport.run_load_hooks(:active_remote, Base)
|
60
63
|
end
|
data/lib/active_remote/bulk.rb
CHANGED
@@ -2,16 +2,12 @@ require 'active_remote/persistence'
|
|
2
2
|
|
3
3
|
module ActiveRemote
|
4
4
|
module Bulk
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Persistence
|
10
9
|
end
|
11
10
|
|
12
|
-
##
|
13
|
-
# Class methods
|
14
|
-
#
|
15
11
|
module ClassMethods
|
16
12
|
|
17
13
|
# Create multiple records at the same time. Returns a collection of active
|
@@ -104,7 +100,7 @@ module ActiveRemote
|
|
104
100
|
#
|
105
101
|
def parse_records(*records)
|
106
102
|
records.flatten!
|
107
|
-
|
103
|
+
|
108
104
|
if records.first.respond_to?(:attributes)
|
109
105
|
records.collect!(&:attributes)
|
110
106
|
else
|
data/lib/active_remote/config.rb
CHANGED
@@ -2,7 +2,6 @@ require 'active_support/ordered_options'
|
|
2
2
|
|
3
3
|
module ActiveRemote
|
4
4
|
class Config < ::ActiveSupport::OrderedOptions
|
5
|
-
|
6
5
|
def initialize(options = {})
|
7
6
|
super
|
8
7
|
|
@@ -16,8 +15,7 @@ module ActiveRemote
|
|
16
15
|
|
17
16
|
def include_root_in_json=(true_or_false)
|
18
17
|
self[:include_root_in_json] = !!true_or_false
|
19
|
-
|
18
|
+
ActiveRemote::Base.include_root_in_json = self[:include_root_in_json]
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
21
|
end
|
data/lib/active_remote/dirty.rb
CHANGED
@@ -4,12 +4,12 @@ require 'active_model/dirty'
|
|
4
4
|
#
|
5
5
|
module ActiveRemote
|
6
6
|
module Dirty
|
7
|
-
|
8
|
-
klass.class_eval do
|
9
|
-
include ActiveModel::Dirty
|
7
|
+
extend ActiveSupport::Concern
|
10
8
|
|
11
|
-
|
12
|
-
|
9
|
+
included do
|
10
|
+
include ActiveModel::Dirty
|
11
|
+
|
12
|
+
attr_accessor :_active_remote_track_changes
|
13
13
|
end
|
14
14
|
|
15
15
|
def disable_dirty_tracking
|
data/lib/active_remote/dsl.rb
CHANGED
@@ -2,12 +2,7 @@ require 'active_support/inflector'
|
|
2
2
|
|
3
3
|
module ActiveRemote
|
4
4
|
module DSL
|
5
|
-
|
6
|
-
klass.class_eval do
|
7
|
-
extend ::ActiveRemote::DSL::ClassMethods
|
8
|
-
include ::ActiveRemote::DSL::InstanceMethods
|
9
|
-
end
|
10
|
-
end
|
5
|
+
extend ActiveSupport::Concern
|
11
6
|
|
12
7
|
module ClassMethods
|
13
8
|
|
@@ -106,23 +101,20 @@ module ActiveRemote
|
|
106
101
|
end
|
107
102
|
end
|
108
103
|
|
109
|
-
|
110
|
-
#
|
111
|
-
module InstanceMethods
|
112
|
-
|
113
|
-
private
|
104
|
+
private
|
114
105
|
|
115
|
-
|
116
|
-
|
117
|
-
|
106
|
+
# Private convenience methods for accessing DSL methods in instances
|
107
|
+
#
|
108
|
+
def _publishable_attributes
|
109
|
+
self.class.publishable_attributes
|
110
|
+
end
|
118
111
|
|
119
|
-
|
120
|
-
|
121
|
-
|
112
|
+
def _service_name
|
113
|
+
self.class.service_name
|
114
|
+
end
|
122
115
|
|
123
|
-
|
124
|
-
|
125
|
-
end
|
116
|
+
def _service_class
|
117
|
+
self.class.service_class
|
126
118
|
end
|
127
119
|
end
|
128
120
|
end
|
data/lib/active_remote/errors.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
module ActiveRemote
|
2
2
|
module Integration
|
3
|
-
|
4
|
-
klass.class_eval do
|
5
|
-
unless singleton_methods.include?(:cache_timestamp_format)
|
6
|
-
##
|
7
|
-
# :singleton-method:
|
8
|
-
# Indicates the format used to generate the timestamp format in the cache key.
|
9
|
-
# This is +:number+, by default.
|
10
|
-
#
|
11
|
-
def self.cache_timestamp_format
|
12
|
-
:number
|
13
|
-
end
|
3
|
+
extend ActiveSupport::Concern
|
14
4
|
|
5
|
+
included do
|
6
|
+
unless singleton_methods.include?(:cache_timestamp_format)
|
7
|
+
##
|
8
|
+
# :singleton-method:
|
9
|
+
# Indicates the format used to generate the timestamp format in the cache key.
|
10
|
+
# This is +:number+, by default.
|
11
|
+
#
|
12
|
+
def self.cache_timestamp_format
|
13
|
+
:number
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -2,28 +2,23 @@ require 'active_remote/rpc'
|
|
2
2
|
|
3
3
|
module ActiveRemote
|
4
4
|
module Persistence
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
remote.errors.clear
|
20
|
-
end
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include RPC
|
9
|
+
|
10
|
+
# Allow users to create callbacks around a `save` call.
|
11
|
+
#
|
12
|
+
define_model_callbacks :save, :create, :update
|
13
|
+
|
14
|
+
# Before a save occurs, ensure that we
|
15
|
+
# clear out the errors list.
|
16
|
+
#
|
17
|
+
set_callback :save, :before do |remote|
|
18
|
+
remote.errors.clear
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
|
-
##
|
25
|
-
# Class methods
|
26
|
-
#
|
27
22
|
module ClassMethods
|
28
23
|
|
29
24
|
# Creates a remote record through the service.
|
@@ -73,202 +68,197 @@ module ActiveRemote
|
|
73
68
|
end
|
74
69
|
end
|
75
70
|
|
76
|
-
|
77
|
-
#
|
71
|
+
# Deletes the record from the service (the service determines if the
|
72
|
+
# record is hard or soft deleted) and freezes this instance to indicate
|
73
|
+
# that no changes should be made (since they can't be persisted). If the
|
74
|
+
# record was not deleted, it will have error messages indicating what went
|
75
|
+
# wrong. Returns the frozen instance.
|
78
76
|
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# that no changes should be made (since they can't be persisted). If the
|
83
|
-
# record was not deleted, it will have error messages indicating what went
|
84
|
-
# wrong. Returns the frozen instance.
|
85
|
-
#
|
86
|
-
def delete
|
87
|
-
raise ReadOnlyRemoteRecord if readonly?
|
88
|
-
execute(:delete, "guid" => read_attribute("guid"))
|
77
|
+
def delete
|
78
|
+
raise ReadOnlyRemoteRecord if readonly?
|
79
|
+
execute(:delete, "guid" => read_attribute("guid"))
|
89
80
|
|
90
|
-
|
91
|
-
|
81
|
+
return success? ? freeze : false
|
82
|
+
end
|
92
83
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
84
|
+
# Deletes the record from the service (the service determines if the
|
85
|
+
# record is hard or soft deleted) and freezes this instance to indicate
|
86
|
+
# that no changes should be made (since they can't be persisted). If the
|
87
|
+
# record was not deleted, an exception will be raised. Returns the frozen
|
88
|
+
# instance.
|
89
|
+
#
|
90
|
+
def delete!
|
91
|
+
delete
|
92
|
+
raise ActiveRemoteError.new(errors.to_s) if has_errors?
|
93
|
+
end
|
103
94
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
95
|
+
# Destroys (hard deletes) the record from the service and freezes this
|
96
|
+
# instance to indicate that no changes should be made (since they can't
|
97
|
+
# be persisted). If the record was not deleted, it will have error
|
98
|
+
# messages indicating what went wrong. Returns the frozen instance.
|
99
|
+
#
|
100
|
+
def destroy
|
101
|
+
raise ReadOnlyRemoteRecord if readonly?
|
102
|
+
execute(:destroy, "guid" => read_attribute("guid"))
|
112
103
|
|
113
|
-
|
114
|
-
|
104
|
+
return success? ? freeze : false
|
105
|
+
end
|
115
106
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
107
|
+
# Destroys (hard deletes) the record from the service and freezes this
|
108
|
+
# instance to indicate that no changes should be made (since they can't
|
109
|
+
# be persisted). If the record was not deleted, an exception will be
|
110
|
+
# raised. Returns the frozen instance.
|
111
|
+
#
|
112
|
+
def destroy!
|
113
|
+
destroy
|
114
|
+
raise ActiveRemoteError.new(errors.to_s) if has_errors?
|
115
|
+
end
|
125
116
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
117
|
+
# Returns true if the record has errors; otherwise, returns false.
|
118
|
+
#
|
119
|
+
def has_errors?
|
120
|
+
return respond_to?(:errors) && errors.present?
|
121
|
+
end
|
131
122
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
123
|
+
# Instantiate a record with the given remote attributes. Generally used
|
124
|
+
# when retrieving records that already exist, so @new_record is set to false.
|
125
|
+
#
|
126
|
+
def instantiate(record)
|
127
|
+
skip_dirty_tracking do
|
128
|
+
assign_attributes(record)
|
129
|
+
end
|
139
130
|
|
140
|
-
|
131
|
+
run_callbacks :initialize
|
141
132
|
|
142
|
-
|
143
|
-
|
144
|
-
|
133
|
+
@new_record = false
|
134
|
+
self
|
135
|
+
end
|
145
136
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
137
|
+
# Returns true if the remote record hasn't been saved yet; otherwise,
|
138
|
+
# returns false.
|
139
|
+
#
|
140
|
+
def new_record?
|
141
|
+
@new_record
|
142
|
+
end
|
152
143
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
144
|
+
# Returns true if the remote record has been saved; otherwise, returns false.
|
145
|
+
#
|
146
|
+
def persisted?
|
147
|
+
return ! new_record?
|
148
|
+
end
|
158
149
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
150
|
+
# Sets the instance to be a readonly object
|
151
|
+
#
|
152
|
+
def readonly!
|
153
|
+
@readonly = true
|
154
|
+
end
|
164
155
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
156
|
+
# Returns true if the remote class or remote record is readonly; otherwise, returns false.
|
157
|
+
def readonly?
|
158
|
+
self.class.readonly? || @readonly
|
159
|
+
end
|
169
160
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
161
|
+
# Saves the remote record.
|
162
|
+
#
|
163
|
+
# If it is a new record, it will be created through the service, otherwise
|
164
|
+
# the existing record gets updated.
|
165
|
+
#
|
166
|
+
# The service will run any validations and if any of them fail, will return
|
167
|
+
# the record with error messages indicating what went wrong.
|
168
|
+
#
|
169
|
+
# Also runs any before/after save callbacks that are defined.
|
170
|
+
#
|
171
|
+
def save
|
172
|
+
run_callbacks :save do
|
173
|
+
create_or_update
|
184
174
|
end
|
175
|
+
end
|
185
176
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
177
|
+
# Saves the remote record.
|
178
|
+
#
|
179
|
+
# If it is a new record, it will be created through the service, otherwise
|
180
|
+
# the existing record gets updated.
|
181
|
+
#
|
182
|
+
# The service will run any validations. If any of them fail (e.g. error
|
183
|
+
# messages are returned), an ActiveRemote::RemoteRecordNotSaved is raised.
|
184
|
+
#
|
185
|
+
# Also runs any before/after save callbacks that are defined.
|
186
|
+
#
|
187
|
+
def save!
|
188
|
+
save || raise(RemoteRecordNotSaved)
|
189
|
+
end
|
199
190
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
191
|
+
# Returns true if the record doesn't have errors; otherwise, returns false.
|
192
|
+
#
|
193
|
+
def success?
|
194
|
+
return ! has_errors?
|
195
|
+
end
|
205
196
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
197
|
+
# Updates the attributes of the remote record from the passed-in hash and
|
198
|
+
# saves the remote record. If the object is invalid, it will have error
|
199
|
+
# messages and false will be returned.
|
200
|
+
#
|
201
|
+
def update_attributes(attributes)
|
202
|
+
assign_attributes(attributes)
|
203
|
+
save
|
204
|
+
end
|
214
205
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
206
|
+
# Updates the attributes of the remote record from the passed-in hash and
|
207
|
+
# saves the remote record. If the object is invalid, an
|
208
|
+
# ActiveRemote::RemoteRecordNotSaved is raised.
|
209
|
+
#
|
210
|
+
def update_attributes!(attributes)
|
211
|
+
assign_attributes(attributes)
|
212
|
+
save!
|
213
|
+
end
|
223
214
|
|
224
|
-
|
215
|
+
private
|
225
216
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
217
|
+
# Handles creating a remote object and serializing it's attributes and
|
218
|
+
# errors from the response.
|
219
|
+
#
|
220
|
+
def create
|
221
|
+
run_callbacks :create do
|
222
|
+
# Use the getter here so we get the type casting.
|
223
|
+
new_attributes = attributes
|
224
|
+
new_attributes.delete("guid")
|
234
225
|
|
235
|
-
|
226
|
+
execute(:create, new_attributes)
|
236
227
|
|
237
|
-
|
238
|
-
|
228
|
+
assign_attributes(last_response.to_hash)
|
229
|
+
add_errors_from_response
|
239
230
|
|
240
|
-
|
241
|
-
|
242
|
-
end
|
231
|
+
@new_record = has_errors?
|
232
|
+
success?
|
243
233
|
end
|
234
|
+
end
|
244
235
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
236
|
+
# Deterines whether the record should be created or updated. New records
|
237
|
+
# are created, existing records are updated. If the record is marked as
|
238
|
+
# readonly, an ActiveRemote::ReadOnlyRemoteRecord is raised.
|
239
|
+
#
|
240
|
+
def create_or_update
|
241
|
+
raise ReadOnlyRemoteRecord if readonly?
|
242
|
+
new_record? ? create : update
|
243
|
+
end
|
253
244
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
245
|
+
# Handles updating a remote object and serializing it's attributes and
|
246
|
+
# errors from the response. Only attributes with the given attribute names
|
247
|
+
# (plus :guid) will be updated. Defaults to all attributes.
|
248
|
+
#
|
249
|
+
def update(attribute_names = @attributes.keys)
|
250
|
+
run_callbacks :update do
|
251
|
+
# Use the getter here so we get the type casting.
|
252
|
+
updated_attributes = attributes
|
253
|
+
updated_attributes.slice!(*attribute_names)
|
254
|
+
updated_attributes.merge!("guid" => self[:guid])
|
264
255
|
|
265
|
-
|
256
|
+
execute(:update, updated_attributes)
|
266
257
|
|
267
|
-
|
268
|
-
|
258
|
+
assign_attributes(last_response.to_hash)
|
259
|
+
add_errors_from_response
|
269
260
|
|
270
|
-
|
271
|
-
end
|
261
|
+
success?
|
272
262
|
end
|
273
263
|
end
|
274
264
|
end
|
data/lib/active_remote/rpc.rb
CHANGED
@@ -1,15 +1,9 @@
|
|
1
|
-
require 'active_remote/serializers/protobuf'
|
2
|
-
|
3
1
|
module ActiveRemote
|
4
2
|
module RPC
|
5
|
-
|
6
|
-
klass.class_eval do
|
7
|
-
extend ::ActiveRemote::RPC::ClassMethods
|
8
|
-
include ::ActiveRemote::Serializers::Protobuf
|
9
|
-
end
|
10
|
-
end
|
3
|
+
extend ActiveSupport::Concern
|
11
4
|
|
12
5
|
module ClassMethods
|
6
|
+
|
13
7
|
# Execute an RPC call to the remote service and return the raw response.
|
14
8
|
#
|
15
9
|
def remote_call(rpc_method, request_args)
|
@@ -23,8 +17,7 @@ module ActiveRemote
|
|
23
17
|
def request(rpc_method, request_args)
|
24
18
|
return request_args unless request_args.is_a?(Hash)
|
25
19
|
|
26
|
-
|
27
|
-
build_message(message_class, request_args)
|
20
|
+
request_type(rpc_method).new(request_args)
|
28
21
|
end
|
29
22
|
|
30
23
|
# Return the class applicable to the request for the given rpc method.
|
data/lib/active_remote/search.rb
CHANGED
@@ -3,14 +3,13 @@ require 'active_remote/rpc'
|
|
3
3
|
|
4
4
|
module ActiveRemote
|
5
5
|
module Search
|
6
|
-
|
7
|
-
klass.class_eval do
|
8
|
-
extend ::ActiveRemote::Search::ClassMethods
|
9
|
-
include ::ActiveRemote::Persistence
|
10
|
-
include ::ActiveRemote::RPC
|
6
|
+
extend ActiveSupport::Concern
|
11
7
|
|
12
|
-
|
13
|
-
|
8
|
+
included do
|
9
|
+
include Persistence
|
10
|
+
include RPC
|
11
|
+
|
12
|
+
define_model_callbacks :search
|
14
13
|
end
|
15
14
|
|
16
15
|
module ClassMethods
|
@@ -2,10 +2,10 @@ require 'active_remote/serializers/json'
|
|
2
2
|
|
3
3
|
module ActiveRemote
|
4
4
|
module Serialization
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Serializers::JSON
|
9
9
|
end
|
10
10
|
|
11
11
|
# Examine the given response and add any errors to our internal errors
|
data/lib/active_remote.rb
CHANGED
@@ -1,25 +1,17 @@
|
|
1
1
|
require 'active_attr'
|
2
2
|
require 'active_model'
|
3
|
+
require 'active_support'
|
3
4
|
require 'protobuf'
|
4
5
|
|
5
|
-
require 'active_support/core_ext/array'
|
6
|
-
require 'active_support/core_ext/hash'
|
7
|
-
require 'active_support/inflector'
|
8
|
-
require 'active_support/json'
|
9
|
-
|
10
|
-
require 'active_remote/core_ext/date_time'
|
11
|
-
require 'active_remote/core_ext/date'
|
12
|
-
require 'active_remote/core_ext/integer'
|
13
|
-
|
14
6
|
require 'active_remote/base'
|
15
7
|
require 'active_remote/config'
|
8
|
+
require 'active_remote/core_ext'
|
16
9
|
require 'active_remote/errors'
|
17
|
-
|
18
10
|
require 'active_remote/version'
|
19
11
|
|
20
12
|
module ActiveRemote
|
21
13
|
def self.config
|
22
|
-
@config ||=
|
14
|
+
@config ||= Config.new
|
23
15
|
end
|
24
16
|
|
25
17
|
# Initialize the config
|
@@ -22,11 +22,9 @@ describe ActiveRemote::RPC do
|
|
22
22
|
|
23
23
|
describe ".request" do
|
24
24
|
let(:attributes) { Hash.new }
|
25
|
-
let(:message) { double(:message) }
|
26
25
|
|
27
26
|
it "builds an RPC request" do
|
28
|
-
Tag.
|
29
|
-
Tag.request(:create, attributes)
|
27
|
+
Tag.request(:create, attributes).should eq Generic::Remote::Tag.new(attributes)
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
@@ -7,9 +7,9 @@ message Category {
|
|
7
7
|
optional string name = 2;
|
8
8
|
repeated Error errors = 3;
|
9
9
|
optional string user_guid = 4;
|
10
|
-
optional string author_guid =
|
11
|
-
optional string chief_editor_guid =
|
12
|
-
optional string editor_guid =
|
10
|
+
optional string author_guid = 5;
|
11
|
+
optional string chief_editor_guid = 6;
|
12
|
+
optional string editor_guid = 7;
|
13
13
|
}
|
14
14
|
|
15
15
|
message Categories {
|
@@ -25,10 +25,10 @@ module Generic
|
|
25
25
|
# Message Fields
|
26
26
|
#
|
27
27
|
class Author
|
28
|
-
optional
|
29
|
-
optional
|
28
|
+
optional :string, :guid, 1
|
29
|
+
optional :string, :name, 2
|
30
30
|
repeated ::Generic::Error, :errors, 3
|
31
|
-
optional
|
31
|
+
optional :string, :user_guid, 4
|
32
32
|
end
|
33
33
|
|
34
34
|
class Authors
|
@@ -36,8 +36,8 @@ module Generic
|
|
36
36
|
end
|
37
37
|
|
38
38
|
class AuthorRequest
|
39
|
-
repeated
|
40
|
-
repeated
|
39
|
+
repeated :string, :guid, 1
|
40
|
+
repeated :string, :name, 2
|
41
41
|
end
|
42
42
|
|
43
43
|
|
@@ -26,12 +26,12 @@ module Generic
|
|
26
26
|
# Message Fields
|
27
27
|
#
|
28
28
|
class Post
|
29
|
-
optional
|
30
|
-
optional
|
31
|
-
optional
|
29
|
+
optional :string, :guid, 1
|
30
|
+
optional :string, :name, 2
|
31
|
+
optional :string, :author_guid, 3
|
32
32
|
optional ::Generic::Remote::Category, :category, 4
|
33
33
|
repeated ::Generic::Error, :errors, 5
|
34
|
-
optional
|
34
|
+
optional :string, :user_guid, 6
|
35
35
|
end
|
36
36
|
|
37
37
|
class Posts
|
@@ -39,10 +39,10 @@ module Generic
|
|
39
39
|
end
|
40
40
|
|
41
41
|
class PostRequest
|
42
|
-
repeated
|
43
|
-
repeated
|
44
|
-
repeated
|
45
|
-
repeated
|
42
|
+
repeated :string, :guid, 1
|
43
|
+
repeated :string, :name, 2
|
44
|
+
repeated :string, :author_guid, 3
|
45
|
+
repeated :string, :user_guid, 4
|
46
46
|
end
|
47
47
|
|
48
48
|
|
@@ -25,8 +25,8 @@ module Generic
|
|
25
25
|
# Message Fields
|
26
26
|
#
|
27
27
|
class Tag
|
28
|
-
optional
|
29
|
-
optional
|
28
|
+
optional :string, :guid, 1
|
29
|
+
optional :string, :name, 2
|
30
30
|
repeated ::Generic::Error, :errors, 3
|
31
31
|
end
|
32
32
|
|
@@ -35,8 +35,8 @@ module Generic
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class TagRequest
|
38
|
-
repeated
|
39
|
-
repeated
|
38
|
+
repeated :string, :guid, 1
|
39
|
+
repeated :string, :name, 2
|
40
40
|
end
|
41
41
|
|
42
42
|
|
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:
|
4
|
+
version: 2.0.0.rc1
|
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-02-
|
11
|
+
date: 2014-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_attr
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '0.8'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '0.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '3.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '3.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: protobuf
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 3.0.0.alpha
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 3.0.0.alpha
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: better_receive
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,6 +172,7 @@ files:
|
|
172
172
|
- lib/active_remote/base.rb
|
173
173
|
- lib/active_remote/bulk.rb
|
174
174
|
- lib/active_remote/config.rb
|
175
|
+
- lib/active_remote/core_ext.rb
|
175
176
|
- lib/active_remote/core_ext/date.rb
|
176
177
|
- lib/active_remote/core_ext/date_time.rb
|
177
178
|
- lib/active_remote/core_ext/integer.rb
|
@@ -186,7 +187,6 @@ files:
|
|
186
187
|
- lib/active_remote/search.rb
|
187
188
|
- lib/active_remote/serialization.rb
|
188
189
|
- lib/active_remote/serializers/json.rb
|
189
|
-
- lib/active_remote/serializers/protobuf.rb
|
190
190
|
- lib/active_remote/version.rb
|
191
191
|
- spec/core_ext/date_time_spec.rb
|
192
192
|
- spec/lib/active_remote/association_spec.rb
|
@@ -201,7 +201,6 @@ files:
|
|
201
201
|
- spec/lib/active_remote/search_spec.rb
|
202
202
|
- spec/lib/active_remote/serialization_spec.rb
|
203
203
|
- spec/lib/active_remote/serializers/json_spec.rb
|
204
|
-
- spec/lib/active_remote/serializers/protobuf_spec.rb
|
205
204
|
- spec/spec_helper.rb
|
206
205
|
- spec/support/definitions/author.proto
|
207
206
|
- spec/support/definitions/post.proto
|
@@ -235,9 +234,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
235
234
|
version: '0'
|
236
235
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
237
236
|
requirements:
|
238
|
-
- - '
|
237
|
+
- - '>'
|
239
238
|
- !ruby/object:Gem::Version
|
240
|
-
version:
|
239
|
+
version: 1.3.1
|
241
240
|
requirements: []
|
242
241
|
rubyforge_project:
|
243
242
|
rubygems_version: 2.2.1
|
@@ -258,7 +257,6 @@ test_files:
|
|
258
257
|
- spec/lib/active_remote/search_spec.rb
|
259
258
|
- spec/lib/active_remote/serialization_spec.rb
|
260
259
|
- spec/lib/active_remote/serializers/json_spec.rb
|
261
|
-
- spec/lib/active_remote/serializers/protobuf_spec.rb
|
262
260
|
- spec/spec_helper.rb
|
263
261
|
- spec/support/definitions/author.proto
|
264
262
|
- spec/support/definitions/post.proto
|
@@ -1,98 +0,0 @@
|
|
1
|
-
module ActiveRemote
|
2
|
-
module Serializers
|
3
|
-
module Protobuf
|
4
|
-
ATTRIBUTE_TYPES = {
|
5
|
-
::Protobuf::Field::DoubleField => Float,
|
6
|
-
::Protobuf::Field::FloatField => Float,
|
7
|
-
::Protobuf::Field::Int32Field => Integer,
|
8
|
-
::Protobuf::Field::Int64Field => Integer,
|
9
|
-
::Protobuf::Field::Uint32Field => Integer,
|
10
|
-
::Protobuf::Field::Uint64Field => Integer,
|
11
|
-
::Protobuf::Field::Sint32Field => Integer,
|
12
|
-
::Protobuf::Field::Sint64Field => Integer,
|
13
|
-
::Protobuf::Field::Fixed32Field => Float,
|
14
|
-
::Protobuf::Field::Fixed64Field => Float,
|
15
|
-
::Protobuf::Field::Sfixed32Field => Float,
|
16
|
-
::Protobuf::Field::Sfixed64Field => Float,
|
17
|
-
::Protobuf::Field::StringField => String,
|
18
|
-
::Protobuf::Field::BytesField => String,
|
19
|
-
::Protobuf::Field::BoolField => ::ActiveAttr::Typecasting::Boolean,
|
20
|
-
:bool => ::ActiveAttr::Typecasting::Boolean,
|
21
|
-
:double => Float,
|
22
|
-
:float => Float,
|
23
|
-
:int32 => Integer,
|
24
|
-
:int64 => Integer,
|
25
|
-
:string => String
|
26
|
-
}.freeze
|
27
|
-
|
28
|
-
def self.included(klass)
|
29
|
-
klass.extend ::ActiveRemote::Serializers::Protobuf::ClassMethods
|
30
|
-
end
|
31
|
-
|
32
|
-
module ClassMethods
|
33
|
-
# Recursively build messages from a hash of attributes.
|
34
|
-
# TODO: Pull this functionality into the protobuf gem.
|
35
|
-
#
|
36
|
-
def build_message(message_class, attributes)
|
37
|
-
attributes.inject(message_class.new) do |message, (key, value)|
|
38
|
-
if field = message.get_field_by_name(key) || message.get_ext_field_by_name(key)
|
39
|
-
|
40
|
-
# Override the value based on the field type where issues
|
41
|
-
# exist in the protobuf gem.
|
42
|
-
#
|
43
|
-
if field.repeated?
|
44
|
-
collection = [ value ]
|
45
|
-
collection.flatten!
|
46
|
-
collection.compact!
|
47
|
-
collection.map! { |value| coerce(value, field) }
|
48
|
-
value = collection
|
49
|
-
else
|
50
|
-
value = coerce(value, field)
|
51
|
-
end
|
52
|
-
|
53
|
-
if field.message? && field.repeated?
|
54
|
-
value = value.map do |attributes|
|
55
|
-
attributes.is_a?(Hash) ? build_message(field.type, attributes) : attributes
|
56
|
-
end
|
57
|
-
elsif field.message?
|
58
|
-
value = value.is_a?(Hash) ? build_message(field.type, value) : value
|
59
|
-
end
|
60
|
-
|
61
|
-
message.method("#{key}=").call(value)
|
62
|
-
end
|
63
|
-
|
64
|
-
message
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def coerce(value, field)
|
69
|
-
return value if value.nil?
|
70
|
-
return value.to_i if field.enum?
|
71
|
-
|
72
|
-
protobuf_field_type = ::ActiveRemote::Serializers::Protobuf::ATTRIBUTE_TYPES[field.type]
|
73
|
-
|
74
|
-
case
|
75
|
-
when protobuf_field_type == ::ActiveAttr::Typecasting::Boolean then
|
76
|
-
if value == 1
|
77
|
-
return true
|
78
|
-
elsif value == 0
|
79
|
-
return false
|
80
|
-
end
|
81
|
-
when protobuf_field_type == Integer then
|
82
|
-
return value.to_i
|
83
|
-
when protobuf_field_type == Float then
|
84
|
-
return value.to_f
|
85
|
-
when protobuf_field_type == String then
|
86
|
-
return value.to_s
|
87
|
-
end
|
88
|
-
|
89
|
-
return value
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def build_message(message_class, attributes)
|
94
|
-
self.class.build_message(message_class, attributes)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ActiveRemote::Serializers::Protobuf do
|
4
|
-
describe ".build_message" do
|
5
|
-
it "coerces the attribute value to a compatible type"
|
6
|
-
|
7
|
-
it "builds a protobuf message"
|
8
|
-
|
9
|
-
context "when the message doesn't have a field matching a given attribute" do
|
10
|
-
it "skips the attribute"
|
11
|
-
end
|
12
|
-
|
13
|
-
context "when a field is repeated" do
|
14
|
-
it "converts the attribute to a collection"
|
15
|
-
it "coerces the attribute value(s) to a compatible type"
|
16
|
-
end
|
17
|
-
|
18
|
-
context "when the field is an enum" do
|
19
|
-
it "converts the attribute into an integer"
|
20
|
-
end
|
21
|
-
|
22
|
-
context "when a field is a message" do
|
23
|
-
let(:attributes) { { :category => category } }
|
24
|
-
let(:category) { { :name => 'foo' } }
|
25
|
-
let(:category_message) { Generic::Remote::Category.new(category) }
|
26
|
-
|
27
|
-
context "and the value is a hash" do
|
28
|
-
it "builds new messages with the value(s)" do
|
29
|
-
message = ::ActiveRemote::Base.build_message(Generic::Remote::Post, attributes)
|
30
|
-
message.category.should eq (category_message)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context "and the value is a message" do
|
35
|
-
let(:attributes) { { :category => category_message } }
|
36
|
-
|
37
|
-
it "returns the value" do
|
38
|
-
message = ::ActiveRemote::Base.build_message(Generic::Remote::Post, attributes)
|
39
|
-
message.category.should eq (category_message)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context "and the field is repeated" do
|
44
|
-
context "and the value is a hash" do
|
45
|
-
let(:attributes) { { :records => [ tag ] } }
|
46
|
-
let(:tag) { { :name => 'foo' } }
|
47
|
-
let(:tag_message) { Generic::Remote::Tag.new(tag) }
|
48
|
-
|
49
|
-
it "builds new messages with the value(s)" do
|
50
|
-
message = ::ActiveRemote::Base.build_message(Generic::Remote::Tags, attributes)
|
51
|
-
message.records.first.should eq (tag_message)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context "and the value is a message" do
|
56
|
-
let(:attributes) { { :records => [ tag_message ] } }
|
57
|
-
let(:tag_message) { Generic::Remote::Tag.new }
|
58
|
-
|
59
|
-
it "returns the value" do
|
60
|
-
message = ::ActiveRemote::Base.build_message(Generic::Remote::Tags, attributes)
|
61
|
-
message.records.first.should eq (tag_message)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
describe ".coerce" do
|
69
|
-
context "when field_type is :bool" do
|
70
|
-
context "and value is 1" do
|
71
|
-
it "returns true"
|
72
|
-
end
|
73
|
-
|
74
|
-
context "and value is 0" do
|
75
|
-
it "returns false"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context "when the field_type is :int32" do
|
80
|
-
it "returns an integer"
|
81
|
-
end
|
82
|
-
|
83
|
-
context "when the field_type is :int64" do
|
84
|
-
it "returns an integer"
|
85
|
-
end
|
86
|
-
|
87
|
-
context "when the field_type is :double" do
|
88
|
-
it "returns a float"
|
89
|
-
end
|
90
|
-
|
91
|
-
context "when the field_type is :string" do
|
92
|
-
it "returns a string"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|