2015-04-17 00:28:38 +00:00
|
|
|
# Copyright 2015 Google Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
require 'representable/json'
|
|
|
|
require 'representable/json/hash'
|
|
|
|
require 'base64'
|
2015-07-25 05:36:01 +00:00
|
|
|
require 'date'
|
2015-04-17 00:28:38 +00:00
|
|
|
|
|
|
|
module Google
|
|
|
|
module Apis
|
|
|
|
module Core
|
2017-12-28 19:10:23 +00:00
|
|
|
# Support for serializing hashes + property value/nil/unset tracking
|
2015-04-17 00:28:38 +00:00
|
|
|
# To be included in representers as a feature.
|
|
|
|
# @private
|
|
|
|
module JsonRepresentationSupport
|
|
|
|
def self.included(base)
|
|
|
|
base.extend(JsonSupport)
|
|
|
|
end
|
|
|
|
|
|
|
|
# @private
|
|
|
|
module JsonSupport
|
|
|
|
# Returns a customized getter function for Representable. Allows
|
|
|
|
# indifferent hash/attribute access.
|
|
|
|
#
|
|
|
|
# @param [String] name Property name
|
|
|
|
# @return [Proc]
|
|
|
|
def getter_fn(name)
|
|
|
|
ivar_name = "@#{name}".to_sym
|
|
|
|
lambda do |_|
|
2016-02-25 03:19:42 +00:00
|
|
|
if respond_to?(:fetch)
|
|
|
|
fetch(name, instance_variable_get(ivar_name))
|
2015-04-17 00:28:38 +00:00
|
|
|
else
|
|
|
|
instance_variable_get(ivar_name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns a customized function for Representable that checks whether or not
|
|
|
|
# an attribute should be serialized. Allows proper patch semantics by distinguishing
|
|
|
|
# between nil & unset values
|
|
|
|
#
|
|
|
|
# @param [String] name Property name
|
|
|
|
# @return [Proc]
|
|
|
|
def if_fn(name)
|
|
|
|
ivar_name = "@#{name}".to_sym
|
|
|
|
lambda do |opts|
|
2016-08-17 21:38:25 +00:00
|
|
|
if opts[:user_options] && opts[:user_options][:skip_undefined]
|
2015-04-17 00:28:38 +00:00
|
|
|
if respond_to?(:key?)
|
|
|
|
self.key?(name) || instance_variable_defined?(ivar_name)
|
|
|
|
else
|
|
|
|
instance_variable_defined?(ivar_name)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_default_options(name, options)
|
|
|
|
if options[:base64]
|
2016-04-25 17:49:00 +00:00
|
|
|
options[:render_filter] = ->(value, _doc, *_args) { value.nil? ? nil : Base64.urlsafe_encode64(value) }
|
2015-04-17 00:28:38 +00:00
|
|
|
options[:parse_filter] = ->(fragment, _doc, *_args) { Base64.urlsafe_decode64(fragment) }
|
|
|
|
end
|
2016-08-17 22:27:23 +00:00
|
|
|
if options[:numeric_string]
|
|
|
|
options[:render_filter] = ->(value, _doc, *_args) { value.nil? ? nil : value.to_s}
|
|
|
|
options[:parse_filter] = ->(fragment, _doc, *_args) { fragment.to_i }
|
|
|
|
end
|
2015-07-25 05:36:01 +00:00
|
|
|
if options[:type] == DateTime
|
2016-04-25 17:49:00 +00:00
|
|
|
options[:render_filter] = ->(value, _doc, *_args) { value.nil? ? nil : value.is_a?(DateTime) ? value.rfc3339(3) : value.to_s }
|
2015-07-25 05:36:01 +00:00
|
|
|
options[:parse_filter] = ->(fragment, _doc, *_args) { DateTime.parse(fragment) }
|
|
|
|
end
|
2019-05-10 18:09:40 +00:00
|
|
|
if options[:type] == Date
|
|
|
|
options[:render_filter] = ->(value, _doc, *_args) { value.nil? ? nil : value.to_s}
|
|
|
|
options[:parse_filter] = ->(fragment, _doc, *_args) { Date.parse(fragment) }
|
|
|
|
end
|
2015-12-20 22:39:11 +00:00
|
|
|
|
2015-04-17 00:28:38 +00:00
|
|
|
options[:render_nil] = true
|
|
|
|
options[:getter] = getter_fn(name)
|
|
|
|
options[:if] = if_fn(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Define a single value property
|
|
|
|
#
|
|
|
|
# @param [String] name
|
|
|
|
# Property name
|
|
|
|
# @param [Hash] options
|
|
|
|
def property(name, options = {})
|
|
|
|
set_default_options(name, options)
|
|
|
|
super(name, options)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Define a collection property
|
|
|
|
#
|
|
|
|
# @param [String] name
|
|
|
|
# Property name
|
|
|
|
# @param [Hash] options
|
|
|
|
def collection(name, options = {})
|
|
|
|
set_default_options(name, options)
|
|
|
|
super(name, options)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Define a hash property
|
|
|
|
#
|
|
|
|
# @param [String] name
|
|
|
|
# Property name
|
|
|
|
# @param [Hash] options
|
2015-12-20 22:39:11 +00:00
|
|
|
def hash(name = nil, options = nil)
|
|
|
|
return super() unless name # Allow Object.hash
|
2015-04-17 00:28:38 +00:00
|
|
|
set_default_options(name, options)
|
|
|
|
super(name, options)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Base decorator for JSON representers
|
|
|
|
#
|
|
|
|
# @see https://github.com/apotonick/representable
|
|
|
|
class JsonRepresentation < Representable::Decorator
|
|
|
|
include Representable::JSON
|
|
|
|
feature JsonRepresentationSupport
|
|
|
|
end
|
2016-02-25 22:37:00 +00:00
|
|
|
|
|
|
|
module JsonObjectSupport
|
|
|
|
def self.included(base)
|
|
|
|
base.extend(ClassMethods)
|
|
|
|
end
|
|
|
|
|
|
|
|
module ClassMethods
|
|
|
|
def from_json(json)
|
|
|
|
representation = self.const_get(:Representation)
|
|
|
|
representation.new(self.new).from_json(json, unwrap: self)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-19 23:16:22 +00:00
|
|
|
def to_json(*a)
|
2016-02-25 22:37:00 +00:00
|
|
|
representation = self.class.const_get(:Representation)
|
2016-08-17 21:38:25 +00:00
|
|
|
representation.new(self).to_json(user_options: { skip_undefined: true })
|
2016-02-25 22:37:00 +00:00
|
|
|
end
|
|
|
|
end
|
2015-04-17 00:28:38 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|