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
175 176 177 178 |
# File 'lib/firm/serializable.rb', line 175 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.
183 184 185 |
# File 'lib/firm/serializable.rb', line 183 def default_format @default_format ||= :json end |
.default_format=(format) ⇒ Symbol
Set the default output format.
190 191 192 |
# File 'lib/firm/serializable.rb', line 190 def default_format=(format) @default_format = format end |
.deserialize(source, format: Serializable.default_format) ⇒ Object
Deserializes object from source data
540 541 542 |
# File 'lib/firm/serializable.rb', line 540 def self.deserialize(source, format: Serializable.default_format) self[format].load(::IO === source || source.respond_to?(:read) ? source.read : source) end |
.formatters ⇒ Object
156 157 158 |
# File 'lib/firm/serializable.rb', line 156 def formatters @formatters ||= {} end |
.included(base) ⇒ Object
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 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 |
# File 'lib/firm/serializable.rb', line 571 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
164 165 166 167 168 169 170 |
# File 'lib/firm/serializable.rb', line 164 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
152 153 154 |
# File 'lib/firm/serializable.rb', line 152 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
532 533 534 |
# File 'lib/firm/serializable.rb', line 532 def self.serialize(obj, io = nil, pretty: false, format: Serializable.default_format) self[format].dump(obj, io, pretty: pretty) end |
.tls_vars ⇒ Object
148 149 150 |
# File 'lib/firm/serializable.rb', line 148 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 501
|
#from_serialized(hash) ⇒ self
Restores the properties of a deserialized instance.
|
# File 'lib/firm/serializable.rb', line 508
|