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.
@@ -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 { |proto_field| # Do some stuff... }
88
- # attribute_from_proto :status do |proto_field|
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(field, transformer = nil, &blk)
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[field.to_sym] = callable
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, :protobuf_fields
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, :protobuf_fields, :protobuf_message
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
- def convert_column(field, converter = nil, &blk)
23
- warn "[DEPRECATION] `convert_column` is deprecated and will be removed in v1.2. Please use `protoable_attribute` instead."
24
- protoable_attribute(field, converter, &blk)
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
- value = respond_to?(field) ? __send__(field) : nil
102
- hash[field] = _protobuf_convert_attributes_to_fields(field, value)
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
@@ -1,5 +1,5 @@
1
1
  module Protobuf
2
2
  module ActiveRecord
3
- VERSION = "1.1.1"
3
+ VERSION = "1.2.0.rc1"
4
4
  end
5
5
  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 attribute transformer is defined for the field" do
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 attribute transformer is not defined for the field" do
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
- let(:attributes) {
78
- {
79
- :guid => "foo",
80
- :first_name => "bar",
81
- :last_name => "baz",
82
- :email => "foo@test.co"
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
- it "returns a hash of protobuf fields that this object has getters for" do
88
- user.protoable_attributes.should eq protoable_attributes
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
- it "converts attributes values for protobuf messages" do
92
- user.should_receive(:_protobuf_convert_attributes_to_fields).any_number_of_times
93
- user.protoable_attributes
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 = 1;
3
- optional string name = 2;
4
- optional string email = 3;
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 {
@@ -1,2 +1 @@
1
- require 'protobuf'
2
1
  require 'support/protobuf/user.pb'
@@ -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.1.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 00:00:00.000000000 Z
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: 471675617945359118
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: '0'
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