protobuf-activerecord 1.1.1 → 1.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|