Module: FIRM::Serializable
- Included in:
- ID
- Defined in:
- lib/firm/serializable.rb,
lib/firm/serialize/id.rb,
lib/firm/serialize/core.rb,
lib/firm/serializer/xml.rb,
lib/firm/serializer/json.rb,
lib/firm/serializer/yaml.rb
Overview
Mixin module providing (de-)serialization support for user defined classes.
Defined Under Namespace
Modules: AliasManagement, Aliasing, CoreExt, JSON, SerializeClassMethods, SerializeInstanceMethods, XML, YAML Classes: Exception, ID, MethodResolver, Property
Constant Summary collapse
- TLS_VARS_KEY =
:firm_tls_vars.freeze
Class Method Summary collapse
-
.[](format) ⇒ Object
Return a serialization formatting engine.
-
.default_format ⇒ Symbol
Return the default output format symbol id (:json, :yaml, :xml).
-
.default_format=(format) ⇒ Symbol
Set the default output format.
-
.deserialize(source, format: Serializable.default_format) ⇒ Object
Deserializes object from source data.
- .formatters ⇒ Object
- .included(base) ⇒ Object
-
.register(format, engine) ⇒ Object
Registers a serialization formatting engine.
- .serializables ⇒ Object
-
.serialize(obj, io = nil, pretty: false, format: Serializable.default_format) ⇒ Object
Serialize the given object.
- .tls_vars ⇒ Object
Instance Method Summary collapse
-
#for_serialize(hash, excludes = Set.new) ⇒ Object
Serializes the properties of a serializable instance to the given hash except when the property id is included in excludes.
-
#from_serialized(hash) ⇒ self
Restores the properties of a deserialized instance.
Class Method Details
.[](format) ⇒ Object
Return a serialization formatting engine
210 211 212 213 |
# File 'lib/firm/serializable.rb', line 210 def [](format) ::Kernel.raise ArgumentError, "Format #{format} is not supported." unless formatters.has_key?(format.to_s.downcase) formatters[format.to_s.downcase] end |
.default_format ⇒ Symbol
Return the default output format symbol id (:json, :yaml, :xml). By default returns :json.
218 219 220 |
# File 'lib/firm/serializable.rb', line 218 def default_format @default_format ||= :json end |
.default_format=(format) ⇒ Symbol
Set the default output format.
225 226 227 |
# File 'lib/firm/serializable.rb', line 225 def default_format=(format) @default_format = format end |
.deserialize(source, format: Serializable.default_format) ⇒ Object
Deserializes object from source data
598 599 600 |
# File 'lib/firm/serializable.rb', line 598 def self.deserialize(source, format: Serializable.default_format) self[format].load(::IO === source || source.respond_to?(:read) ? source.read : source) end |
.formatters ⇒ Object
191 192 193 |
# File 'lib/firm/serializable.rb', line 191 def formatters @formatters ||= {} end |
.included(base) ⇒ Object
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
# File 'lib/firm/serializable.rb', line 629 def self.included(base) ::Kernel.raise RuntimeError, "#{self} should only be included in classes" if base.instance_of?(::Module) ::Kernel.raise RuntimeError, "#{self} should be included only once in #{base}" if Serializable.serializables.include?(base.name) # register as serializable class Serializable.serializables << base return if base == Serializable::ID # special case which does not need the rest # provide serialized property definition support # provide serialized classes with their own serialized properties (exclusion) list # and a deserialization finalizer setter/getter base.singleton_class.class_eval do def serializer_properties @serializer_props ||= [] end def excluded_serializer_properties @excluded_serializer_props ||= ::Set.new end def set_deserialize_finalizer(fin) @finalize_from_deserialized = fin end private :set_deserialize_finalizer def get_deserialize_finalizer case @finalize_from_deserialized when Serializable::MethodResolver @finalize_from_deserialized = @finalize_from_deserialized.resolve else @finalize_from_deserialized end end private :get_deserialize_finalizer def find_deserialize_finalizer get_deserialize_finalizer end end base.class_eval do # Initializes a newly allocated instance for subsequent deserialization (optionally initializing # using the given data hash). # The default implementation calls the standard #initialize method without arguments (default constructor) # and leaves the property restoration to a subsequent call to the instance method #from_serialized(data). # Classes that do not support a default constructor can override this class method and # implement a custom initialization scheme. # @param [Object] _data hash-like object containing deserialized property data (symbol keys) # @return [Object] the initialized object def init_from_serialized(_data) initialize self end protected :init_from_serialized # Check if the class has the default deserialize finalizer method defined (a #create method # without arguments). If so install that method as the deserialize finalizer. set_deserialize_finalizer(Serializable::MethodResolver.new(self, :create, true)) end # add class methods base.extend(SerializeClassMethods) # add instance property (de-)serialization methods for base class base.class_eval <<~__CODE def for_serialize(hash, excludes = ::Set.new) #{base.name}.serializer_properties.each { |prop, h| prop.serialize(self, hash, excludes) } hash end protected :for_serialize def from_serialized(hash) #{base.name}.serializer_properties.each { |prop| prop.deserialize(self, hash) } self end protected :from_serialized def finalize_from_serialized if (f = self.class.find_deserialize_finalizer) f.call(self) end self end protected :finalize_from_serialized def self.has_serializer_property?(id) self.serializer_properties.any? { |p| p.id == id.to_sym } end __CODE # add inheritance support base.class_eval do def self.inherited(derived) # add instance property (de-)serialization methods for derived classes derived.class_eval <<~__CODE module SerializerMethods def for_serialize(hash, excludes = ::Set.new) #{derived.name}.serializer_properties.each { |prop| prop.serialize(self, hash, excludes) } super(hash, excludes | #{derived.name}.excluded_serializer_properties) end protected :for_serialize def from_serialized(hash) #{derived.name}.serializer_properties.each { |prop| prop.deserialize(self, hash) } super(hash) end protected :from_serialized end include SerializerMethods __CODE derived.class_eval do def self.has_serializer_property?(id) self.serializer_properties.any? { |p| p.id == id.to_sym } || self.superclass.has_serializer_property?(id) end end # add derived class support for deserialization finalizer derived.singleton_class.class_eval <<~__CODE def find_deserialize_finalizer get_deserialize_finalizer || #{derived.name}.superclass.find_deserialize_finalizer end __CODE # Check if the derived class has the default deserialize finalizer method defined (a #create method # without arguments) defined. If so install that method as the deserialize finalizer (it is expected # this method will call any superclass finalizer that may be defined). derived.class_eval do set_deserialize_finalizer(Serializable::MethodResolver.new(self, :create, true)) end # register as serializable class Serializable.serializables << derived end end # add instance serialization method base.include(SerializeInstanceMethods) end |
.register(format, engine) ⇒ Object
Registers a serialization formatting engine
199 200 201 202 203 204 205 |
# File 'lib/firm/serializable.rb', line 199 def register(format, engine) if formatters.has_key?(format.to_s.downcase) ::Kernel.raise ArgumentError, "Duplicate serialization formatter registration for #{format}" end formatters[format.to_s.downcase] = engine end |
.serializables ⇒ Object
187 188 189 |
# File 'lib/firm/serializable.rb', line 187 def serializables @serializables ||= ::Set.new end |
.serialize(obj, pretty: false, format: Serializable.default_format) ⇒ String .serialize(obj, io, pretty: false, format: Serializable.default_format) ⇒ IO
Serialize the given object
590 591 592 |
# File 'lib/firm/serializable.rb', line 590 def self.serialize(obj, io = nil, pretty: false, format: Serializable.default_format) self[format].dump(obj, io, pretty: pretty) end |
.tls_vars ⇒ Object
183 184 185 |
# File 'lib/firm/serializable.rb', line 183 def tls_vars Thread.current[TLS_VARS_KEY] ||= {} end |
Instance Method Details
#for_serialize(hash, excludes = Set.new) ⇒ Object
Serializes the properties of a serializable instance to the given hash except when the property id is included in excludes.
|
# File 'lib/firm/serializable.rb', line 559
|
#from_serialized(hash) ⇒ self
Restores the properties of a deserialized instance.
|
# File 'lib/firm/serializable.rb', line 566
|