protobuf-activerecord 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -18,7 +18,97 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ Protobuf Active Record's functionality is contained within the `Protoable` module. To endow your Active Record models with the protoable behaviour, simply include it into your model:
22
+
23
+ ```Ruby
24
+
25
+ class User < ActiveRecord::Base
26
+ include Protoable
27
+
28
+ # Your awesome methods...
29
+ #
30
+ end
31
+
32
+ ```
33
+
34
+ Now you can pass protobuf messages to your user model just like you would attributes. Protoable will take care of converting the protobuf message to attributes and continue on with Active Record's normal behavior.
35
+
36
+ ### Field/Attribute mapping
37
+
38
+ Just like Active Record maps database columns to your model's attributes, Protoable maps protobuf fields to your model's attributes.
39
+
40
+ Given a table that looks like this:
41
+
42
+ ```Ruby
43
+
44
+ create_table :users do |t|
45
+ t.string :first_name
46
+ t.string :last_name
47
+ t.string :email
48
+ t.integer :account_id
49
+
50
+ t.timestamps
51
+ end
52
+
53
+ ```
54
+
55
+ and a protobuf message that looks like this:
56
+
57
+ ```Ruby
58
+
59
+ class UserMessage < ::Protobuf::Message
60
+ optional ::Protobuf::Field::StringField, :first_name, 1
61
+ optional ::Protobuf::Field::StringField, :last_name, 2
62
+ optional ::Protobuf::Field::StringField, :email, 3
63
+ optional ::Protobuf::Field::IntegerField, :account_id, 4
64
+ end
65
+
66
+ ```
67
+
68
+ Protoable will map the `first_name`, `last_name`, `email`, & `account_id` columns, skipping the timestamp columns. Repeated fields and fields that are nil will not be mapped.
69
+
70
+ **Dates**
71
+
72
+ Since Protocol Buffer messages don't support sending date, time, or datetime fields, Protoable expects date, time, and datetime fields to be sent as integers. Just like Active Record handles translating Ruby dates, times, and datetimes into the proper database column types, Protoable will handle converting dates, times, and dateimes to and from integers mapping protobuf message fields.
73
+
74
+ Picking up our users table example again, if you wanted to add a `created_at` field to your protobuf message, if you add it as an integer field, Protoable will handle the conversions for you:
75
+
76
+ ```Ruby
77
+
78
+ class UserMessage < ::Protobuf::Message
79
+ optional ::Protobuf::Field::StringField, :first_name, 1
80
+ optional ::Protobuf::Field::StringField, :last_name, 2
81
+ optional ::Protobuf::Field::StringField, :email, 3
82
+ optional ::Protobuf::Field::IntegerField, :account_id, 4
83
+
84
+ # Add a datetime field as an integer and Protoable will map it for you
85
+ optional ::Protobuf::Field::IntegerField, :created_at, 5
86
+ end
87
+
88
+ ```
89
+
90
+ **Mass-assignment**
91
+
92
+ If a model has protected attributes defined, Protoable will skip any fields that map to them. Likewise, if there are accessible attributes defined, only they will be mapped.
93
+
94
+ ### Persistence
95
+
96
+ Protoable doesn't alter Active Record's normal persistence methods. It simply adds to ability to pass protobuf messages to them in place of an attributes hash.
97
+
98
+ ### Serialization
99
+
100
+ In addition to mapping protobuf message fields to Active Record objects when creating or updating records, Protoable also provides the ability to serialize Active Record objects to protobuf messages. Simply tell Protoable the protobuf message that should be used and it will take care of the rest:
101
+
102
+ ```Ruby
103
+
104
+ class User < ActiveRecord::Base
105
+ # Configures Protoable to use the UserMessage class and adds a :to_proto method.
106
+ protobuf_message :user_message
107
+ end
108
+
109
+ ```
110
+
111
+ Once the desired protobuf message has been specified, Protoable adds a `to_proto` method to the model. Calling `to_proto` will automatically convert the model to the specified protobuf message using the same attribute to field mapping it uses to create and update objects from protobuf messages.
22
112
 
23
113
  ## Contributing
24
114
 
@@ -10,6 +10,9 @@ module Protoable
10
10
  class << self
11
11
  attr_accessor :_protobuf_columns, :_protobuf_column_types,
12
12
  :_protobuf_column_transformers, :_protobuf_field_converters
13
+
14
+ alias_method :convert_field_to_column, :convert_field
15
+ alias_method :transform_column_from_proto, :transform_column
13
16
  end
14
17
 
15
18
  @_protobuf_columns = {}
@@ -51,21 +51,39 @@ module Protoable
51
51
  attributes
52
52
  end
53
53
 
54
+ # :nodoc:
55
+ def create(attributes, options = {}, &block)
56
+ attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
57
+
58
+ super(attributes, options)
59
+ end
60
+
61
+ # :nodoc:
62
+ def create!(attributes, options = {}, &block)
63
+ attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
64
+
65
+ super(attributes, options)
66
+ end
67
+
54
68
  # Creates an object from the given protobuf message, if it's valid. The
55
69
  # newly created object is returned if it was successfully saved or not.
56
70
  #
57
- def create_from_proto(proto)
71
+ def create_from_proto(proto, options = {})
58
72
  attributes = attributes_from_proto(proto)
59
73
 
60
74
  yield(attributes) if block_given?
61
75
 
62
- record = self.new(attributes)
63
-
64
- record.save! if record.valid?
65
- return record
76
+ self.create(attributes, options)
66
77
  end
67
78
  end
68
79
 
80
+ # :nodoc:
81
+ def assign_attributes(attributes, options = {})
82
+ attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
83
+
84
+ super(attributes, options)
85
+ end
86
+
69
87
  # Calls up to the class version of the method.
70
88
  #
71
89
  def attributes_from_proto(proto)
@@ -79,16 +97,29 @@ module Protoable
79
97
  destroy
80
98
  end
81
99
 
100
+ # :nodoc:
101
+ def update_attributes(attributes, options = {})
102
+ attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
103
+
104
+ super(attributes, options)
105
+ end
106
+
107
+ # :nodoc:
108
+ def update_attributes!(attributes, options = {})
109
+ attributes = attributes_from_proto(proto) if attributes.is_a?(::Protobuf::Message)
110
+
111
+ super(attributes, options)
112
+ end
113
+
82
114
  # Update a record from a proto message. Accepts an optional block.
83
115
  # If block is given, yields the attributes that would be updated.
84
116
  #
85
- def update_from_proto(proto)
117
+ def update_from_proto(proto, options = {})
86
118
  attributes = attributes_from_proto(proto)
87
119
 
88
120
  yield(attributes) if block_given?
89
121
 
90
- assign_attributes(attributes)
91
- return valid? ? save! : false
122
+ update_attributes(attributes, options)
92
123
  end
93
124
  end
94
125
  end
@@ -7,6 +7,8 @@ module Protoable
7
7
  klass.class_eval do
8
8
  class << self
9
9
  attr_accessor :_protobuf_column_converters, :protobuf_fields
10
+
11
+ alias_method :convert_column_to_field, :convert_column
10
12
  end
11
13
 
12
14
  @_protobuf_column_converters = {}
@@ -1,5 +1,5 @@
1
1
  module Protobuf
2
2
  module ActiveRecord
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
@@ -78,7 +78,7 @@ describe Protoable::Persistence do
78
78
  end
79
79
 
80
80
  context "when an error occurs while saving" do
81
- before { User.any_instance.stub(:save!).and_raise(RuntimeError) }
81
+ before { User.any_instance.stub(:create).and_raise(RuntimeError) }
82
82
 
83
83
  it "raises an exception" do
84
84
  expect { User.create_from_proto(proto) }.to raise_exception
@@ -112,7 +112,7 @@ describe Protoable::Persistence do
112
112
 
113
113
  describe "#update_from_proto" do
114
114
  it "updates the object with attributes from the given protobuf message" do
115
- user.should_receive(:assign_attributes).with(user_attributes)
115
+ user.should_receive(:assign_attributes).with(user_attributes, {})
116
116
  user.update_from_proto(proto)
117
117
  end
118
118
 
@@ -133,13 +133,13 @@ describe Protoable::Persistence do
133
133
 
134
134
  context "when saving is successful" do
135
135
  it "returns true" do
136
- user.stub(:save!).and_return(true)
136
+ user.stub(:assign_attributes).and_return(true)
137
137
  user.update_from_proto(proto).should be_true
138
138
  end
139
139
  end
140
140
 
141
141
  context "when an error occurs while saving" do
142
- before { user.stub(:save!).and_raise(RuntimeError) }
142
+ before { user.stub(:assign_attributes).and_raise(RuntimeError) }
143
143
 
144
144
  it "raises an exception" do
145
145
  expect { user.update_from_proto }.to raise_exception
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protobuf-activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-26 00:00:00.000000000 Z
12
+ date: 2012-10-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -222,7 +222,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
222
222
  version: '0'
223
223
  segments:
224
224
  - 0
225
- hash: -307556624232627597
225
+ hash: -2932429429413082945
226
226
  required_rubygems_version: !ruby/object:Gem::Requirement
227
227
  none: false
228
228
  requirements:
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  version: '0'
232
232
  segments:
233
233
  - 0
234
- hash: -307556624232627597
234
+ hash: -2932429429413082945
235
235
  requirements: []
236
236
  rubyforge_project:
237
237
  rubygems_version: 1.8.24