This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/plugins/serialization.rb is in ruby-sequel 3.33.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
module Sequel
  module Plugins
    # Sequel's built in Serialization plugin allows you to keep serialized
    # ruby objects in the database, while giving you deserialized objects
    # when you call an accessor.
    #
    # This plugin works by keeping the serialized value in the values, and
    # adding a @deserialized_values hash.  The reader method for serialized columns
    # will check the @deserialized_values for the value, return it if present,
    # or deserialized the entry in @values and return it.  The writer method will
    # set the @deserialized_values entry.  This plugin adds a before_save hook
    # that serializes all @deserialized_values to @values.
    #
    # You can specify the serialization format as a pair of serializer/deserializer
    # callable objects.  You can also specify the serialization format as a single
    # symbol, if such a symbol has a registered serializer/deserializer pair in the
    # plugin.  By default, the plugin registers the :marshal, :yaml, and :json
    # serialization formats.  To register your own serialization formats, use
    # Sequel::Plugins::Serialization.register_format.
    # If you use yaml or json format, you need to require the libraries, Sequel
    # does not do the requiring for you.
    #
    # You can specify the columns to serialize when loading the plugin, or later
    # using the serialize_attributes class method.
    #
    # Because of how this plugin works, it must be used inside each model class
    # that needs serialization, after any set_dataset method calls in that class.
    # Otherwise, it is possible that the default column accessors will take
    # precedence.
    #
    # == Example
    #
    #   require 'sequel'
    #   # Require json, as the plugin doesn't require it for you.
    #   require 'json'
    #
    #   # Register custom serializer/deserializer pair
    #   Sequel::Plugins::Serialization.register_format(:reverse,
    #     lambda{|v| v.reverse},
    #     lambda{|v| v.reverse})
    #
    #   class User < Sequel::Model
    #     # Built-in format support when loading the plugin
    #     plugin :serialization, :json, :permissions
    #
    #     # Built-in format support after loading the plugin using serialize_attributes
    #     plugin :serialization
    #     serialize_attributes :marshal, :permissions
    #
    #     # Use custom registered serialization format just like built-in format
    #     serialize_attributes :reverse, :password
    #
    #     # Use a custom serializer/deserializer pair without registering
    #     serialize_attributes [lambda{|v| v.reverse}, lambda{|v| v.reverse}], :password
    #   end
    #   user = User.create
    #   user.permissions = { :global => 'read-only' }
    #   user.save
    module Serialization
      # The default serializers supported by the serialization module.
      # Use register_format to add serializers to this hash.
      REGISTERED_FORMATS = {}

      # Set up the column readers to do deserialization and the column writers
      # to save the value in deserialized_values.
      def self.apply(model, *args)
        model.instance_eval do
          @deserialization_map = {}
          @serialization_map = {}
        end
      end
      
      # Automatically call serialize_attributes with the format and columns unless
      # no columns were provided.
      def self.configure(model, format=nil, *columns)
        model.serialize_attributes(format, *columns) unless columns.empty?
      end

      # Register a serializer/deserializer pair with a format symbol, to allow
      # models to pick this format by name.  Both serializer and deserializer
      # should be callable objects.
      def self.register_format(format, serializer, deserializer)
        REGISTERED_FORMATS[format] = [serializer, deserializer]
      end
      register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')}, lambda{|v| Marshal.load(v.unpack('m')[0]) rescue Marshal.load(v)})
      register_format(:yaml, lambda{|v| v.to_yaml}, lambda{|v| YAML.load(v)})
      register_format(:json, lambda{|v| v.to_json}, lambda{|v| JSON.parse(v)})

      module ClassMethods
        # A hash with column name symbols and callable values, with the value
        # called to deserialize the column.
        attr_reader :deserialization_map

        # A hash with column name symbols and callable values, with the value
        # called to serialize the column.
        attr_reader :serialization_map

        # Module to store the serialized column accessor methods, so they can
        # call be overridden and call super to get the serialization behavior
        attr_accessor :serialization_module

        # Copy the serialization_map and deserialization map into the subclass.
        def inherited(subclass)
          super
          sm = serialization_map.dup
          dsm = deserialization_map.dup
          subclass.instance_eval do
            @deserialization_map = dsm
            @serialization_map = sm
          end
        end
        
        # Create instance level reader that deserializes column values on request,
        # and instance level writer that stores new deserialized values.
        def serialize_attributes(format, *columns)
          if format.is_a?(Symbol)
            unless format = REGISTERED_FORMATS[format]
              raise(Error, "Unsupported serialization format: #{format} (valid formats: #{REGISTERED_FORMATS.keys.map{|k| k.inspect}.join})")
            end
          end
          serializer, deserializer = format
          raise(Error, "No columns given.  The serialization plugin requires you specify which columns to serialize") if columns.empty?
          define_serialized_attribute_accessor(serializer, deserializer, *columns)
        end
        
        # The columns that will be serialized.  This is only for
        # backwards compatibility, use serialization_map in new code.
        def serialized_columns
          serialization_map.keys
        end

        private

        # Add serializated attribute acessor methods to the serialization_module
        def define_serialized_attribute_accessor(serializer, deserializer, *columns)
          m = self
          include(self.serialization_module ||= Module.new) unless serialization_module
          serialization_module.class_eval do
            columns.each do |column|
              m.serialization_map[column] = serializer
              m.deserialization_map[column] = deserializer
              define_method(column) do 
                if deserialized_values.has_key?(column)
                  deserialized_values[column]
                else
                  deserialized_values[column] = deserialize_value(column, super())
                end
              end
              define_method("#{column}=") do |v| 
                changed_columns << column unless changed_columns.include?(column)
                deserialized_values[column] = v
              end
            end
          end
        end
      end

      module InstanceMethods
        # Hash of deserialized values, used as a cache.
        attr_reader :deserialized_values

        # Set @deserialized_values to the empty hash
        def initialize_set(values)
          @deserialized_values = {}
          super
        end

        # Serialize deserialized values before saving
        def before_save
          serialize_deserialized_values
          super
        end
        
        # Initialization the deserialized values for objects retrieved from the database.
        def set_values(*)
          @deserialized_values ||= {}
          super
        end

        private

        # Empty the deserialized values when refreshing.
        def _refresh(*)
          @deserialized_values = {}
          super
        end

        # Deserialize the column value.  Called when the model column accessor is called to
        # return a deserialized value.
        def deserialize_value(column, v)
          unless v.nil?
            raise Sequel::Error, "no entry in deserialization_map for #{column.inspect}" unless callable = model.deserialization_map[column]
            callable.call(v)
          end
        end

        # Serialize all deserialized values
        def serialize_deserialized_values
          deserialized_values.each{|k,v| @values[k] = serialize_value(k, v)}
        end

        # Serialize the column value.  Called before saving to ensure the serialized value
        # is saved in the database.
        def serialize_value(column, v)
          unless v.nil?
            raise Sequel::Error, "no entry in serialization_map for #{column.inspect}" unless callable = model.serialization_map[column]
            callable.call(v)
          end
        end
      end
    end
  end
end