protobuf-activerecord 2.1.0 → 3.0.0.pre
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 +6 -14
- data/Gemfile +0 -4
- data/lib/protobuf-activerecord.rb +26 -3
- data/lib/protobuf/active_record/attribute_methods.rb +35 -0
- data/lib/protobuf/active_record/columns.rb +74 -0
- data/lib/protobuf/active_record/config.rb +11 -0
- data/lib/protobuf/active_record/errors.rb +23 -0
- data/lib/protobuf/active_record/mass_assignment_security.rb +16 -0
- data/lib/protobuf/active_record/mass_assignment_security/persistence.rb +57 -0
- data/lib/protobuf/active_record/mass_assignment_security/transformation.rb +27 -0
- data/lib/protobuf/active_record/model.rb +32 -0
- data/lib/protobuf/active_record/persistence.rb +55 -0
- data/lib/protobuf/active_record/railtie.rb +11 -0
- data/lib/protobuf/active_record/scope.rb +121 -0
- data/lib/protobuf/active_record/serialization.rb +194 -0
- data/lib/protobuf/active_record/transformation.rb +155 -0
- data/lib/protobuf/active_record/validations.rb +43 -0
- data/lib/protobuf/{activerecord → active_record}/version.rb +1 -1
- data/protobuf-activerecord.gemspec +4 -5
- data/spec/{protoable → protobuf/active_record}/columns_spec.rb +2 -2
- data/spec/{protoable → protobuf/active_record}/persistence_spec.rb +1 -1
- data/spec/{protoable → protobuf/active_record}/scope_spec.rb +1 -8
- data/spec/{protoable → protobuf/active_record}/serialization_spec.rb +2 -2
- data/spec/{protoable → protobuf/active_record}/transformation_spec.rb +12 -12
- data/spec/support/models/user.rb +1 -1
- metadata +59 -68
- data/lib/protobuf/activerecord/protoable.rb +0 -19
- data/lib/protobuf/activerecord/protoable/columns.rb +0 -56
- data/lib/protobuf/activerecord/protoable/errors.rb +0 -22
- data/lib/protobuf/activerecord/protoable/persistence.rb +0 -56
- data/lib/protobuf/activerecord/protoable/scope.rb +0 -121
- data/lib/protobuf/activerecord/protoable/serialization.rb +0 -190
- data/lib/protobuf/activerecord/protoable/transformation.rb +0 -158
- data/lib/protobuf/activerecord/protoable/validations.rb +0 -39
- data/lib/protobuf/activerecord/protobuf_ext/message.rb +0 -16
@@ -1,22 +0,0 @@
|
|
1
|
-
module Protoable
|
2
|
-
|
3
|
-
# = Protoable errors
|
4
|
-
#
|
5
|
-
# Generic Protoable exception class
|
6
|
-
class ProtoableError < StandardError
|
7
|
-
end
|
8
|
-
|
9
|
-
# Raised by Protoable.attribute_from_proto when the transformer method
|
10
|
-
# given is not callable.
|
11
|
-
class AttributeTransformerError < ProtoableError
|
12
|
-
end
|
13
|
-
|
14
|
-
# Raised by Protoable.field_from_record when the convert method
|
15
|
-
# given not callable.
|
16
|
-
class FieldTransformerError < ProtoableError
|
17
|
-
end
|
18
|
-
|
19
|
-
# Raised by Protoable.field_scope when given scope is not defined.
|
20
|
-
class SearchScopeError < ProtoableError
|
21
|
-
end
|
22
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module Protoable
|
2
|
-
module Persistence
|
3
|
-
def self.included(klass)
|
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
|
17
|
-
end
|
18
|
-
|
19
|
-
module ClassMethods
|
20
|
-
# :nodoc:
|
21
|
-
def create(attributes, options = {}, &block)
|
22
|
-
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
23
|
-
|
24
|
-
super(attributes, options)
|
25
|
-
end
|
26
|
-
|
27
|
-
# :nodoc:
|
28
|
-
def create!(attributes, options = {}, &block)
|
29
|
-
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
30
|
-
|
31
|
-
super(attributes, options)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# :nodoc:
|
36
|
-
def assign_attributes(attributes, options = {})
|
37
|
-
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
38
|
-
|
39
|
-
super(attributes, options)
|
40
|
-
end
|
41
|
-
|
42
|
-
# :nodoc:
|
43
|
-
def update_attributes(attributes, options = {})
|
44
|
-
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
45
|
-
|
46
|
-
super(attributes, options)
|
47
|
-
end
|
48
|
-
|
49
|
-
# :nodoc:
|
50
|
-
def update_attributes!(attributes, options = {})
|
51
|
-
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
52
|
-
|
53
|
-
super(attributes, options)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,121 +0,0 @@
|
|
1
|
-
module Protoable
|
2
|
-
module Scope
|
3
|
-
def self.extended(klass)
|
4
|
-
klass.class_eval do
|
5
|
-
class << self
|
6
|
-
alias_method :by_fields, :search_scope
|
7
|
-
alias_method :scope_from_proto, :search_scope
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
# Define fields that should be searchable via `search_scope`. Accepts a
|
13
|
-
# protobuf field and an already defined scope. If no scope is specified,
|
14
|
-
# the scope will be the field name, prefixed with `by_` (e.g. when the
|
15
|
-
# field is :guid, the scope will be :by_guid).
|
16
|
-
#
|
17
|
-
# Optionally, a parser can be provided that will be called, passing the
|
18
|
-
# field value as an argument. This allows custom data parsers to be used
|
19
|
-
# so that they don't have to be handled by scopes. Parsers can be procs,
|
20
|
-
# lambdas, or symbolized method names and must accept the value of the
|
21
|
-
# field as a parameter.
|
22
|
-
#
|
23
|
-
# > **Deprecated usage**: Previous versions required the scope to be passed
|
24
|
-
# as a second argument. This has been replaced with the new hash-style
|
25
|
-
# options or simply relying on the defaults. While it will still work
|
26
|
-
# until v3.0 is released, it has been deprecated.
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# Examples:
|
30
|
-
#
|
31
|
-
# class User < ActiveRecord::Base
|
32
|
-
# scope :by_guid, lambda { |*guids| where(:guid => guids) }
|
33
|
-
# scope :custom_guid_scope, lambda { |*guids| where(:guid => guids) }
|
34
|
-
#
|
35
|
-
# # Equivalent to `field_scope :guid, :by_guid`
|
36
|
-
# field_scope :guid
|
37
|
-
#
|
38
|
-
# # With a custom scope
|
39
|
-
# field_scope :guid, :scope => :custom_guid_scope
|
40
|
-
#
|
41
|
-
# # With a custom parser that converts the value to an integer
|
42
|
-
# field_scope :guid, :scope => :custom_guid_scope, :parser => lambda { |value| value.to_i }
|
43
|
-
# end
|
44
|
-
#
|
45
|
-
def field_scope(field, *args)
|
46
|
-
# TODO: For backwards compatibility. Remove this in the next major release.
|
47
|
-
options = args.extract_options!
|
48
|
-
|
49
|
-
scope_name = case
|
50
|
-
when args.present? then
|
51
|
-
warn "WARNING: Passing scopes directly to field_scope is deprecated and will be removed in 3.0. Use :scope => xxx instead."
|
52
|
-
args.first
|
53
|
-
when options.include?(:scope) then
|
54
|
-
options[:scope]
|
55
|
-
else
|
56
|
-
# When no scope is defined, assume the scope is the field, prefixed with `by_`
|
57
|
-
:"by_#{field}"
|
58
|
-
end
|
59
|
-
searchable_fields[field] = scope_name
|
60
|
-
|
61
|
-
searchable_field_parsers[field] = options[:parser] if options[:parser]
|
62
|
-
end
|
63
|
-
|
64
|
-
# :noapi:
|
65
|
-
def parse_search_values(proto, field)
|
66
|
-
value = proto.__send__(field)
|
67
|
-
|
68
|
-
if searchable_field_parsers[field]
|
69
|
-
parser = searchable_field_parsers[field]
|
70
|
-
|
71
|
-
if parser.respond_to?(:to_sym)
|
72
|
-
value = self.__send__(parser.to_sym, value)
|
73
|
-
else
|
74
|
-
value = parser.call(value)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
values = [ value ].flatten
|
79
|
-
values.map!(&:to_i) if proto.get_field_by_name(field).enum?
|
80
|
-
values
|
81
|
-
end
|
82
|
-
|
83
|
-
# Builds and returns a Arel relation based on the fields that are present
|
84
|
-
# in the given protobuf message using the searchable fields to determine
|
85
|
-
# what scopes to use. Provides several aliases for variety.
|
86
|
-
#
|
87
|
-
# Examples:
|
88
|
-
#
|
89
|
-
# # Search starting with the default scope and searchable fields
|
90
|
-
# User.search_scope(request)
|
91
|
-
# User.by_fields(request)
|
92
|
-
# User.scope_from_proto(request)
|
93
|
-
#
|
94
|
-
def search_scope(proto)
|
95
|
-
relation = scoped # Get an ARel relation to build off of
|
96
|
-
|
97
|
-
searchable_fields.each do |field, scope_name|
|
98
|
-
next unless proto.respond_to_and_has_and_present?(field)
|
99
|
-
|
100
|
-
unless self.respond_to?(scope_name)
|
101
|
-
raise Protoable::SearchScopeError, "Undefined scope :#{scope_name}."
|
102
|
-
end
|
103
|
-
|
104
|
-
search_values = parse_search_values(proto, field)
|
105
|
-
relation = relation.__send__(scope_name, *search_values)
|
106
|
-
end
|
107
|
-
|
108
|
-
return relation
|
109
|
-
end
|
110
|
-
|
111
|
-
# :noapi:
|
112
|
-
def searchable_fields
|
113
|
-
@_searchable_fields ||= {}
|
114
|
-
end
|
115
|
-
|
116
|
-
# :noapi:
|
117
|
-
def searchable_field_parsers
|
118
|
-
@_searchable_field_parsers ||= {}
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
@@ -1,190 +0,0 @@
|
|
1
|
-
require 'heredity/inheritable_class_instance_variables'
|
2
|
-
|
3
|
-
module Protoable
|
4
|
-
module Serialization
|
5
|
-
def self.included(klass)
|
6
|
-
klass.extend Protoable::Serialization::ClassMethods
|
7
|
-
klass.__send__(:include, ::Heredity::InheritableClassInstanceVariables)
|
8
|
-
|
9
|
-
klass.class_eval do
|
10
|
-
class << self
|
11
|
-
attr_accessor :_protobuf_field_transformers, :_protobuf_field_options
|
12
|
-
end
|
13
|
-
|
14
|
-
@_protobuf_field_transformers = {}
|
15
|
-
@_protobuf_field_options = {}
|
16
|
-
|
17
|
-
inheritable_attributes :_protobuf_field_transformers, :_protobuf_field_options,
|
18
|
-
:protobuf_message
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
module ClassMethods
|
23
|
-
# :nodoc:
|
24
|
-
def _protobuf_convert_attributes_to_fields(key, value)
|
25
|
-
return value if value.nil?
|
26
|
-
|
27
|
-
value = case
|
28
|
-
when _protobuf_date_column?(key) then
|
29
|
-
value.to_time.to_i
|
30
|
-
when _protobuf_datetime_column?(key) then
|
31
|
-
value.to_i
|
32
|
-
when _protobuf_time_column?(key) then
|
33
|
-
value.to_i
|
34
|
-
when _protobuf_timestamp_column?(key) then
|
35
|
-
value.to_i
|
36
|
-
else
|
37
|
-
value
|
38
|
-
end
|
39
|
-
|
40
|
-
return value
|
41
|
-
end
|
42
|
-
|
43
|
-
# Define a field transformation from a record. Accepts a Symbol,
|
44
|
-
# callable, or block that is called with the record being serialized.
|
45
|
-
#
|
46
|
-
# When given a callable or block, it is directly used to convert the field.
|
47
|
-
#
|
48
|
-
# When a symbol is given, it extracts the method with the same name.
|
49
|
-
#
|
50
|
-
# The callable or method must accept a single parameter, which is the
|
51
|
-
# proto message.
|
52
|
-
#
|
53
|
-
# Examples:
|
54
|
-
# field_from_record :public_key, :convert_public_key_to_proto
|
55
|
-
# field_from_record :status, lambda { |record| # Do some stuff... }
|
56
|
-
# field_from_record :status do |record|
|
57
|
-
# # Do some blocky stuff...
|
58
|
-
# end
|
59
|
-
#
|
60
|
-
def field_from_record(field, transformer = nil, &block)
|
61
|
-
transformer ||= block
|
62
|
-
|
63
|
-
if transformer.is_a?(Symbol)
|
64
|
-
callable = lambda { |value| self.__send__(transformer, value) }
|
65
|
-
else
|
66
|
-
callable = transformer
|
67
|
-
end
|
68
|
-
|
69
|
-
unless callable.respond_to?(:call)
|
70
|
-
raise FieldTransformerError, 'Attribute transformers need a callable or block!'
|
71
|
-
end
|
72
|
-
|
73
|
-
_protobuf_field_transformers[field.to_sym] = callable
|
74
|
-
end
|
75
|
-
|
76
|
-
# Define the protobuf message class that should be used to serialize the
|
77
|
-
# object to protobuf. Accepts a string or symbol and an options hash.
|
78
|
-
#
|
79
|
-
# When protobuf_message is declared, Protoable automatically extracts the
|
80
|
-
# fields from the message and automatically adds a to_proto method that
|
81
|
-
# serializes the object to protobuf.
|
82
|
-
#
|
83
|
-
# The fields that will be automatically serialized can be configured by
|
84
|
-
# passing :only or :except in the options hash. If :only is specified, only
|
85
|
-
# the specified fields will be serialized. If :except is specified, all
|
86
|
-
# field except the specified fields will be serialized.
|
87
|
-
#
|
88
|
-
# By default, deprecated fields will be serialized. To exclude deprecated
|
89
|
-
# fields, pass :deprecated => false in the options hash.
|
90
|
-
#
|
91
|
-
# Examples:
|
92
|
-
# protobuf_message :user_message
|
93
|
-
# protobuf_message "UserMessage"
|
94
|
-
# protobuf_message "Namespaced::UserMessage"
|
95
|
-
# protobuf_message :user_message, :only => [ :guid, :name ]
|
96
|
-
# protobuf_message :user_message, :except => :email_domain
|
97
|
-
# protobuf_message :user_message, :except => :email_domain, :deprecated => false
|
98
|
-
#
|
99
|
-
def protobuf_message(message = nil, options = {})
|
100
|
-
unless message.nil?
|
101
|
-
@protobuf_message = message.to_s.classify.constantize
|
102
|
-
|
103
|
-
self._protobuf_field_options = options
|
104
|
-
|
105
|
-
define_method(:to_proto) do |options = {}|
|
106
|
-
self.class.protobuf_message.new(self.fields_from_record(options))
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
@protobuf_message
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# :nodoc:
|
115
|
-
def _filter_field_attributes(options = {})
|
116
|
-
options = _normalize_options(options)
|
117
|
-
|
118
|
-
fields = _filtered_fields(options)
|
119
|
-
fields &= [ options[:only] ].flatten if options[:only].present?
|
120
|
-
fields -= [ options[:except] ].flatten if options[:except].present?
|
121
|
-
|
122
|
-
fields
|
123
|
-
end
|
124
|
-
|
125
|
-
# :nodoc:
|
126
|
-
def _filtered_fields(options = {})
|
127
|
-
exclude_deprecated = ! options.fetch(:deprecated, true)
|
128
|
-
|
129
|
-
fields = self.class.protobuf_message.all_fields.map do |field|
|
130
|
-
next if field.nil?
|
131
|
-
next if exclude_deprecated && field.deprecated?
|
132
|
-
field.name.to_sym
|
133
|
-
end
|
134
|
-
fields.compact!
|
135
|
-
|
136
|
-
fields
|
137
|
-
end
|
138
|
-
|
139
|
-
# :nodoc:
|
140
|
-
def _normalize_options(options)
|
141
|
-
options ||= {}
|
142
|
-
options[:only] ||= [] if options.fetch(:except, false)
|
143
|
-
options[:except] ||= [] if options.fetch(:only, false)
|
144
|
-
|
145
|
-
self.class._protobuf_field_options.merge(options)
|
146
|
-
end
|
147
|
-
|
148
|
-
# Extracts attributes that correspond to fields on the specified protobuf
|
149
|
-
# message, performing any necessary column conversions on them. Accepts a
|
150
|
-
# hash of options for specifying which fields should be serialized.
|
151
|
-
#
|
152
|
-
# Examples:
|
153
|
-
# fields_from_record(:only => [ :guid, :name ])
|
154
|
-
# fields_from_record(:except => :email_domain)
|
155
|
-
# fields_from_record(:include => :email_domain)
|
156
|
-
# fields_from_record(:except => :email_domain, :deprecated => false)
|
157
|
-
#
|
158
|
-
def fields_from_record(options = {})
|
159
|
-
field_attributes = _filter_field_attributes(options)
|
160
|
-
field_attributes += [ options.fetch(:include, []) ]
|
161
|
-
field_attributes.flatten!
|
162
|
-
field_attributes.compact!
|
163
|
-
field_attributes.uniq!
|
164
|
-
|
165
|
-
field_attributes = field_attributes.inject({}) do |hash, field|
|
166
|
-
if _protobuf_field_transformers.has_key?(field)
|
167
|
-
hash[field] = _protobuf_field_transformers[field].call(self)
|
168
|
-
else
|
169
|
-
value = respond_to?(field) ? __send__(field) : nil
|
170
|
-
hash[field] = _protobuf_convert_attributes_to_fields(field, value)
|
171
|
-
end
|
172
|
-
hash
|
173
|
-
end
|
174
|
-
|
175
|
-
field_attributes
|
176
|
-
end
|
177
|
-
|
178
|
-
private
|
179
|
-
|
180
|
-
# :nodoc:
|
181
|
-
def _protobuf_convert_attributes_to_fields(field, value)
|
182
|
-
self.class._protobuf_convert_attributes_to_fields(field, value)
|
183
|
-
end
|
184
|
-
|
185
|
-
# :nodoc:
|
186
|
-
def _protobuf_field_transformers
|
187
|
-
self.class._protobuf_field_transformers
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
@@ -1,158 +0,0 @@
|
|
1
|
-
require 'heredity/inheritable_class_instance_variables'
|
2
|
-
|
3
|
-
module Protoable
|
4
|
-
module Transformation
|
5
|
-
def self.included(klass)
|
6
|
-
klass.extend Protoable::Transformation::ClassMethods
|
7
|
-
klass.__send__(:include, ::Heredity::InheritableClassInstanceVariables)
|
8
|
-
|
9
|
-
klass.class_eval do
|
10
|
-
class << self
|
11
|
-
attr_accessor :_protobuf_attribute_transformers
|
12
|
-
end
|
13
|
-
|
14
|
-
@_protobuf_attribute_transformers = {}
|
15
|
-
|
16
|
-
inheritable_attributes :_protobuf_attribute_transformers
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module ClassMethods
|
21
|
-
# Filters accessible attributes that exist in the given protobuf message's
|
22
|
-
# fields or have attribute transformers defined for them.
|
23
|
-
#
|
24
|
-
# Returns a hash of attribute fields with their respective values.
|
25
|
-
#
|
26
|
-
# :nodoc:
|
27
|
-
def _filter_attribute_fields(proto)
|
28
|
-
fields = proto.to_hash
|
29
|
-
fields.select! do |key, value|
|
30
|
-
field = proto.get_field_by_name(key) || proto.get_ext_field_by_name(key)
|
31
|
-
proto.has_field?(key) && !field.repeated?
|
32
|
-
end
|
33
|
-
|
34
|
-
attribute_fields = _filtered_attributes.inject({}) do |hash, column_name|
|
35
|
-
symbolized_column = column_name.to_sym
|
36
|
-
|
37
|
-
if fields.has_key?(symbolized_column) ||
|
38
|
-
_protobuf_attribute_transformers.has_key?(symbolized_column)
|
39
|
-
hash[symbolized_column] = fields[symbolized_column]
|
40
|
-
end
|
41
|
-
|
42
|
-
hash
|
43
|
-
end
|
44
|
-
|
45
|
-
attribute_fields
|
46
|
-
end
|
47
|
-
|
48
|
-
# Filters protected attributes from the available attributes list. When
|
49
|
-
# set through accessible attributes, returns the accessible attributes.
|
50
|
-
# When set through protected attributes, returns the attributes minus any
|
51
|
-
# protected attributes.
|
52
|
-
#
|
53
|
-
# :nodoc:
|
54
|
-
def _filtered_attributes
|
55
|
-
return accessible_attributes.to_a if accessible_attributes.present?
|
56
|
-
|
57
|
-
return self.attribute_names - protected_attributes.to_a
|
58
|
-
end
|
59
|
-
|
60
|
-
# :nodoc:
|
61
|
-
def _protobuf_convert_fields_to_columns(key, value)
|
62
|
-
return value if value.nil?
|
63
|
-
|
64
|
-
value = case
|
65
|
-
when _protobuf_date_column?(key) then
|
66
|
-
convert_int64_to_date(value)
|
67
|
-
when _protobuf_datetime_column?(key) then
|
68
|
-
convert_int64_to_datetime(value)
|
69
|
-
when _protobuf_time_column?(key) then
|
70
|
-
convert_int64_to_time(value)
|
71
|
-
when _protobuf_timestamp_column?(key) then
|
72
|
-
convert_int64_to_time(value)
|
73
|
-
else
|
74
|
-
value
|
75
|
-
end
|
76
|
-
|
77
|
-
return value
|
78
|
-
end
|
79
|
-
|
80
|
-
# Define an attribute transformation from protobuf. Accepts a Symbol,
|
81
|
-
# callable, or block.
|
82
|
-
#
|
83
|
-
# When given a callable or block, it is directly used to convert the field.
|
84
|
-
#
|
85
|
-
# When a symbol is given, it extracts the method with the same name.
|
86
|
-
#
|
87
|
-
# The callable or method must accept a single parameter, which is the
|
88
|
-
# proto message.
|
89
|
-
#
|
90
|
-
# Examples:
|
91
|
-
# attribute_from_proto :public_key, :extract_public_key_from_proto
|
92
|
-
# attribute_from_proto :status, lambda { |proto| # Do some stuff... }
|
93
|
-
# attribute_from_proto :status do |proto|
|
94
|
-
# # Do some blocky stuff...
|
95
|
-
# end
|
96
|
-
#
|
97
|
-
def attribute_from_proto(attribute, transformer = nil, &block)
|
98
|
-
transformer ||= block
|
99
|
-
|
100
|
-
if transformer.is_a?(Symbol)
|
101
|
-
callable = lambda { |value| self.__send__(transformer, value) }
|
102
|
-
else
|
103
|
-
callable = transformer
|
104
|
-
end
|
105
|
-
|
106
|
-
unless callable.respond_to?(:call)
|
107
|
-
raise AttributeTransformerError, 'Attribute transformers need a callable or block!'
|
108
|
-
end
|
109
|
-
|
110
|
-
_protobuf_attribute_transformers[attribute.to_sym] = callable
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
# Creates a hash of attributes from a given protobuf message.
|
115
|
-
#
|
116
|
-
# It converts and transforms field values using the field converters and
|
117
|
-
# attribute transformers, ignoring repeated and nil fields.
|
118
|
-
#
|
119
|
-
def attributes_from_proto(proto)
|
120
|
-
attribute_fields = _filter_attribute_fields(proto)
|
121
|
-
|
122
|
-
attributes = attribute_fields.inject({}) do |hash, (key, value)|
|
123
|
-
if _protobuf_attribute_transformers.has_key?(key)
|
124
|
-
attribute = _protobuf_attribute_transformers[key].call(proto)
|
125
|
-
hash[key] = attribute unless attribute.nil?
|
126
|
-
else
|
127
|
-
hash[key] = _protobuf_convert_fields_to_columns(key, value)
|
128
|
-
end
|
129
|
-
|
130
|
-
hash
|
131
|
-
end
|
132
|
-
|
133
|
-
attributes
|
134
|
-
end
|
135
|
-
|
136
|
-
# :nodoc:
|
137
|
-
def convert_int64_to_time(int64)
|
138
|
-
Time.at(int64.to_i)
|
139
|
-
end
|
140
|
-
|
141
|
-
# :nodoc:
|
142
|
-
def convert_int64_to_date(int64)
|
143
|
-
convert_int64_to_time(int64).utc.to_date
|
144
|
-
end
|
145
|
-
|
146
|
-
# :nodoc:
|
147
|
-
def convert_int64_to_datetime(int64)
|
148
|
-
convert_int64_to_time(int64).to_datetime
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Calls up to the class version of the method.
|
153
|
-
#
|
154
|
-
def attributes_from_proto(proto)
|
155
|
-
self.class.attributes_from_proto(proto)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|