active_remote 1.8.1 → 2.0.0.rc1
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 +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
|