protobuf-activerecord 1.1.1 → 1.2.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.
- data/lib/protobuf/activerecord/protoable/errors.rb +5 -0
- data/lib/protobuf/activerecord/protoable/fields.rb +4 -9
- data/lib/protobuf/activerecord/protoable/persistence.rb +12 -0
- data/lib/protobuf/activerecord/protoable/serialization.rb +46 -7
- data/lib/protobuf/activerecord/version.rb +1 -1
- data/spec/protoable/persistence_spec.rb +2 -2
- data/spec/protoable/serialization_spec.rb +69 -14
- data/spec/support/definitions/user.proto +4 -3
- data/spec/support/protobuf.rb +0 -1
- data/spec/support/protobuf/user.pb.rb +1 -0
- metadata +6 -9
@@ -20,6 +20,11 @@ module Protoable
|
|
20
20
|
# given not callable.
|
21
21
|
class FieldConverterError < ProtoableError
|
22
22
|
end
|
23
|
+
|
24
|
+
# Raised by Protoable.field_from_record when the convert method
|
25
|
+
# given not callable.
|
26
|
+
class FieldTransformerError < ProtoableError
|
27
|
+
end
|
23
28
|
|
24
29
|
# Raised by Protoable.field_scope when given scope is not defined.
|
25
30
|
class SearchScopeError < ProtoableError
|
@@ -84,12 +84,12 @@ module Protoable
|
|
84
84
|
#
|
85
85
|
# Examples:
|
86
86
|
# attribute_from_proto :public_key, :extract_public_key_from_proto
|
87
|
-
# attribute_from_proto :status, lambda { |
|
88
|
-
# attribute_from_proto :status do |
|
87
|
+
# attribute_from_proto :status, lambda { |proto| # Do some stuff... }
|
88
|
+
# attribute_from_proto :status do |proto|
|
89
89
|
# # Do some blocky stuff...
|
90
90
|
# end
|
91
91
|
#
|
92
|
-
def attribute_from_proto(
|
92
|
+
def attribute_from_proto(attribute, transformer = nil, &blk)
|
93
93
|
transformer ||= blk
|
94
94
|
|
95
95
|
if transformer.is_a?(Symbol)
|
@@ -102,12 +102,7 @@ module Protoable
|
|
102
102
|
raise AttributeTransformerError, 'Attribute transformers need a callable or block!'
|
103
103
|
end
|
104
104
|
|
105
|
-
_protobuf_attribute_transformers[
|
106
|
-
end
|
107
|
-
|
108
|
-
def transform_column(field, transformer = nil, &blk)
|
109
|
-
warn "[DEPRECATION] `transform_column` is deprecated and will be removed in v1.2. Please use `attribute_from_proto` instead."
|
110
|
-
attribute_from_proto(field, transformer, &blk)
|
105
|
+
_protobuf_attribute_transformers[attribute.to_sym] = callable
|
111
106
|
end
|
112
107
|
end
|
113
108
|
end
|
@@ -2,6 +2,18 @@ module Protoable
|
|
2
2
|
module Persistence
|
3
3
|
def self.included(klass)
|
4
4
|
klass.extend Protoable::Persistence::ClassMethods
|
5
|
+
|
6
|
+
klass.class_eval do
|
7
|
+
# Override Active Record's initialize method so it can accept a protobuf
|
8
|
+
# message as it's attributes. Need to do it in class_eval block since initialize
|
9
|
+
# is defined in ActiveRecord::Base.
|
10
|
+
# :noapi:
|
11
|
+
def initialize(*args)
|
12
|
+
args[0] = attributes_from_proto(args.first) if args.first.is_a?(::Protobuf::Message)
|
13
|
+
|
14
|
+
super(*args)
|
15
|
+
end
|
16
|
+
end
|
5
17
|
end
|
6
18
|
|
7
19
|
module ClassMethods
|
@@ -8,20 +8,51 @@ module Protoable
|
|
8
8
|
|
9
9
|
klass.class_eval do
|
10
10
|
class << self
|
11
|
-
attr_accessor :_protobuf_attribute_converters,
|
11
|
+
attr_accessor :_protobuf_attribute_converters,
|
12
|
+
:_protobuf_field_transformers, :protobuf_fields
|
12
13
|
end
|
13
14
|
|
14
15
|
@_protobuf_attribute_converters = {}
|
16
|
+
@_protobuf_field_transformers = {}
|
15
17
|
@protobuf_fields = []
|
16
18
|
|
17
|
-
inheritable_attributes :_protobuf_attribute_converters,
|
19
|
+
inheritable_attributes :_protobuf_attribute_converters,
|
20
|
+
:_protobuf_field_transformers, :protobuf_fields, :protobuf_message
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
21
24
|
module ClassMethods
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
# Define a field transformation from a record. Accepts a Symbol,
|
26
|
+
# callable, or block that is called with the record being serialized.
|
27
|
+
#
|
28
|
+
# When given a callable or block, it is directly used to convert the field.
|
29
|
+
#
|
30
|
+
# When a symbol is given, it extracts the method with the same name.
|
31
|
+
#
|
32
|
+
# The callable or method must accept a single parameter, which is the
|
33
|
+
# proto message.
|
34
|
+
#
|
35
|
+
# Examples:
|
36
|
+
# field_from_record :public_key, :convert_public_key_to_proto
|
37
|
+
# field_from_record :status, lambda { |record| # Do some stuff... }
|
38
|
+
# field_from_record :status do |record|
|
39
|
+
# # Do some blocky stuff...
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
def field_from_record(field, transformer = nil, &blk)
|
43
|
+
transformer ||= blk
|
44
|
+
|
45
|
+
if transformer.is_a?(Symbol)
|
46
|
+
callable = lambda { |value| self.__send__(transformer, value) }
|
47
|
+
else
|
48
|
+
callable = transformer
|
49
|
+
end
|
50
|
+
|
51
|
+
unless callable.respond_to?(:call)
|
52
|
+
raise FieldTransformerError, 'Attribute transformers need a callable or block!'
|
53
|
+
end
|
54
|
+
|
55
|
+
_protobuf_field_transformers[field.to_sym] = callable
|
25
56
|
end
|
26
57
|
|
27
58
|
# Define a custom attribute conversion for serialization to protobuf.
|
@@ -98,8 +129,12 @@ module Protoable
|
|
98
129
|
#
|
99
130
|
def protoable_attributes
|
100
131
|
protoable_attributes = protobuf_fields.inject({}) do |hash, field|
|
101
|
-
|
102
|
-
|
132
|
+
if _protobuf_field_transformers.has_key?(field)
|
133
|
+
hash[field] = _protobuf_field_transformers[field].call(self)
|
134
|
+
else
|
135
|
+
value = respond_to?(field) ? __send__(field) : nil
|
136
|
+
hash[field] = _protobuf_convert_attributes_to_fields(field, value)
|
137
|
+
end
|
103
138
|
hash
|
104
139
|
end
|
105
140
|
|
@@ -112,6 +147,10 @@ module Protoable
|
|
112
147
|
self.class._protobuf_convert_attributes_to_fields(field, value)
|
113
148
|
end
|
114
149
|
|
150
|
+
def _protobuf_field_transformers
|
151
|
+
self.class._protobuf_field_transformers
|
152
|
+
end
|
153
|
+
|
115
154
|
def protobuf_fields
|
116
155
|
self.class.protobuf_fields
|
117
156
|
end
|
@@ -31,14 +31,14 @@ describe Protoable::Persistence do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe ".attributes_from_proto" do
|
34
|
-
context "when a
|
34
|
+
context "when a transformer is defined for the attribute" do
|
35
35
|
it "transforms the field value" do
|
36
36
|
attribute_fields = User.attributes_from_proto(proto)
|
37
37
|
attribute_fields[:first_name].should eq user_attributes[:first_name]
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
context "when
|
41
|
+
context "when a transformer is not defined for the attribute" do
|
42
42
|
before {
|
43
43
|
User.stub(:_protobuf_convert_fields_to_columns) do |key, value|
|
44
44
|
value
|
@@ -3,6 +3,38 @@ require 'spec_helper'
|
|
3
3
|
describe Protoable::Serialization do
|
4
4
|
let(:protobuf_message) { UserMessage }
|
5
5
|
|
6
|
+
describe ".field_from_record" do
|
7
|
+
context "when the given converter is a symbol" do
|
8
|
+
let(:callable) { lambda { |value| User.__send__(:extract_first_name) } }
|
9
|
+
|
10
|
+
before { User.field_from_record :first_name, :extract_first_name }
|
11
|
+
|
12
|
+
it "creates a callable method object from the converter" do
|
13
|
+
User.should_receive(:extract_first_name)
|
14
|
+
User._protobuf_field_transformers[:first_name].call(1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when the given converter is not callable" do
|
19
|
+
it "raises an exception" do
|
20
|
+
expect { User.field_from_record :name, nil }.to raise_exception(Protoable::FieldTransformerError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the given transformer is callable" do
|
25
|
+
let(:callable) { lambda { |proto| nil } }
|
26
|
+
|
27
|
+
before {
|
28
|
+
User.stub(:_protobuf_field_transformers).and_return(Hash.new)
|
29
|
+
User.field_from_record :account_id, callable
|
30
|
+
}
|
31
|
+
|
32
|
+
it "adds the given converter to the list of protobuf field transformers" do
|
33
|
+
User._protobuf_field_transformers[:account_id] = callable
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
6
38
|
describe ".protoable_attribute" do
|
7
39
|
context "when the given converter is a hash" do
|
8
40
|
let(:method) { lambda { |value| User.__send__(:convert_base64_to_string, value) } }
|
@@ -47,7 +79,7 @@ describe Protoable::Serialization do
|
|
47
79
|
before { User.protobuf_message(protobuf_message) }
|
48
80
|
|
49
81
|
context "given a value" do
|
50
|
-
let(:protobuf_fields) { [ :guid, :name, :email ] }
|
82
|
+
let(:protobuf_fields) { [ :guid, :name, :email, :email_domain ] }
|
51
83
|
|
52
84
|
it "sets .protobuf_fields" do
|
53
85
|
User.protobuf_fields.should =~ protobuf_fields
|
@@ -74,23 +106,46 @@ describe Protoable::Serialization do
|
|
74
106
|
before { User.protobuf_message(protobuf_message) }
|
75
107
|
|
76
108
|
describe "#protoable_attributes" do
|
77
|
-
|
78
|
-
{
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
109
|
+
context "when a transformer is defined for the field" do
|
110
|
+
let(:attributes) {
|
111
|
+
{
|
112
|
+
:guid => "foo",
|
113
|
+
:first_name => "bar",
|
114
|
+
:last_name => "baz",
|
115
|
+
:email => "foo@test.co"
|
116
|
+
}
|
117
|
+
}
|
118
|
+
let(:protoable_attributes) { { :guid => user.guid, :name => user.name, :email => user.email, :email_domain => 'test.co' } }
|
119
|
+
let(:transformer) { { :email_domain => lambda { |record| record.email.split('@').last } } }
|
120
|
+
|
121
|
+
before {
|
122
|
+
User.stub(:_protobuf_field_transformers).and_return(transformer)
|
83
123
|
}
|
84
|
-
}
|
85
|
-
let(:protoable_attributes) { { :guid => user.guid, :name => user.name, :email => user.email } }
|
86
124
|
|
87
|
-
|
88
|
-
|
125
|
+
it "gets the field from the transformer" do
|
126
|
+
user.protoable_attributes.should eq protoable_attributes
|
127
|
+
end
|
89
128
|
end
|
90
129
|
|
91
|
-
|
92
|
-
|
93
|
-
|
130
|
+
context "when a transformer is not defined for the field" do
|
131
|
+
let(:attributes) {
|
132
|
+
{
|
133
|
+
:guid => "foo",
|
134
|
+
:first_name => "bar",
|
135
|
+
:last_name => "baz",
|
136
|
+
:email => "foo@test.co"
|
137
|
+
}
|
138
|
+
}
|
139
|
+
let(:protoable_attributes) { { :guid => user.guid, :name => user.name, :email => user.email, :email_domain => nil } }
|
140
|
+
|
141
|
+
it "returns a hash of protobuf fields that this object has getters for" do
|
142
|
+
user.protoable_attributes.should eq protoable_attributes
|
143
|
+
end
|
144
|
+
|
145
|
+
it "converts attributes values for protobuf messages" do
|
146
|
+
user.should_receive(:_protobuf_convert_attributes_to_fields).any_number_of_times
|
147
|
+
user.protoable_attributes
|
148
|
+
end
|
94
149
|
end
|
95
150
|
end
|
96
151
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
message UserMessage {
|
2
|
-
optional string guid
|
3
|
-
optional string name
|
4
|
-
optional string email
|
2
|
+
optional string guid = 1;
|
3
|
+
optional string name = 2;
|
4
|
+
optional string email = 3;
|
5
|
+
optional string email_domain = 4;
|
5
6
|
}
|
6
7
|
|
7
8
|
message UserSearchMessage {
|
data/spec/support/protobuf.rb
CHANGED
@@ -17,6 +17,7 @@ class UserMessage
|
|
17
17
|
optional ::Protobuf::Field::StringField, :guid, 1
|
18
18
|
optional ::Protobuf::Field::StringField, :name, 2
|
19
19
|
optional ::Protobuf::Field::StringField, :email, 3
|
20
|
+
optional ::Protobuf::Field::StringField, :email_domain, 4
|
20
21
|
end
|
21
22
|
|
22
23
|
class UserSearchMessage
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protobuf-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.2.0.rc1
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Adam Hutchison
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -240,16 +240,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
240
240
|
version: '0'
|
241
241
|
segments:
|
242
242
|
- 0
|
243
|
-
hash:
|
243
|
+
hash: -3851235925633840978
|
244
244
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
245
245
|
none: false
|
246
246
|
requirements:
|
247
|
-
- - ! '
|
247
|
+
- - ! '>'
|
248
248
|
- !ruby/object:Gem::Version
|
249
|
-
version:
|
250
|
-
segments:
|
251
|
-
- 0
|
252
|
-
hash: 471675617945359118
|
249
|
+
version: 1.3.1
|
253
250
|
requirements: []
|
254
251
|
rubyforge_project:
|
255
252
|
rubygems_version: 1.8.24
|