This file is indexed.

/usr/lib/ruby/vendor_ruby/ramaze/cache/sequel.rb is in ruby-ramaze 2012.12.08-3.

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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
require 'sequel'

module Ramaze
  class Cache
    ##
    # The Sequel cache is a cache system that uses the Sequel database toolkit
    # to store the data in a DBMS supported by Sequel. Examples of these
    # databases are MySQL, SQLite3 and so on. In order to use this cache you'd
    # have to do the following:
    #
    #     Ramaze::Cache.options.view = Ramaze::Cache::Sequel.using(
    #       :connection => Sequel.mysql(
    #         :host     => 'localhost',
    #         :user     => 'user',
    #         :password => 'password',
    #         :database => 'blog'
    #       ),
    #       :table => :blog_sessions
    #     )
    #
    # If you already have an existing connection you can just pass the object to
    # the :connection option instead of creating a new connection manually.
    #
    # Massive thanks to Lars Olsson for patching the original Sequel cache so
    # that it supports multiple connections and other useful features.
    #
    # @example Setting a custom database connection
    #  Ramaze::Cache.options.names.push(:sequel)
    #  Ramaze::Cache.options.sequel = Ramaze::Cache::Sequel.using(
    #    :connection => Sequel.connect(
    #      :adapter  => 'mysql2',
    #      :host     => 'localhost',
    #      :username => 'cache',
    #      :password => 'cache123',
    #      :database => 'ramaze_cache'
    #    )
    #  )
    #
    # @author Lars Olsson
    # @since  18-04-2011
    #
    class Sequel
      include Cache::API
      include Innate::Traited

      # Hash containing the default options
      trait :default => {
        # The default Sequel connection to use
        :connection => nil,

        # Whether or not warnings should be displayed
        :display_warnings => false,

        # The name of the default database table to use
        :table => 'ramaze_cache',

        # The default TTL to use
        :ttl => nil
      }

      # Hash containing all the default options merged with the user specified
      # ones
      attr_accessor :options

      class << self
        attr_accessor :options

        ##
        # This method returns a subclass of Ramaze::Cache::Sequel with the
        # provided options set. This is necessary because Ramaze expects a class
        # and not an instance of a class for its cache option.
        #
        # You can provide any parameters you want, but those not used by the
        # cache will not get stored. No parameters are mandatory. Any missing
        # parameters will be replaced by default values.
        #
        # @example
        #  ##
        #  # This will create a mysql session cache in the blog
        #  # database in the table blog_sessions
        #  # Please note that the permissions on the database must
        #  # be set up correctly before you can just create a new table
        #  #
        #  Ramaze.options.cache.session = Ramaze::Cache::Sequel.using(
        #    :connection => Sequel.mysql(
        #      :host     =>'localhost',
        #      :user     =>'user',
        #      :password =>'password',
        #      :database =>'blog'
        #    ),
        #    :table => :blog_sessions
        #  )
        #
        # @author Lars Olsson
        # @since  18-04-2011
        # @param  [Object] options A hash containing the options to use
        # @option options [Object] :connection a Sequel database object
        #  (Sequel::Database) You can use any parameters that Sequel supports for
        #  this object. If this option is left unset, a Sqlite memory database
        #  will be used.
        # @option options [String] :table The table name you want to use for the
        #  cache. Can be either a String or a Symbol. If this option is left
        #  unset, a table called ramaze_cache will be used.
        # @option options [Fixnum] :ttl Setting this value will override
        #  Ramaze's default setting for when a particular cache item will be
        #  invalidated. By default this setting is not used and the cache uses
        #  the values provided by Ramaze, but if you want to use this setting it
        #  should be set to an integer representing the number of seconds before
        #  a cache item becomes invalidated.
        # @option options [TrueClass] :display_warnings When this option is set
        #  to true, failure to serialiaze or deserialize cache items will produce
        #  a warning in the Ramaze log. This option is set to false by default.
        #  Please note that certain objects (for instance Procs) cannot be
        #  serialized by ruby and therefore cannot be cached by this cache class.
        #  Setting this option to true is a good way to find out if the stuff you
        #  are trying to cache is affected by this. Failure to
        #  serialize/deserialize a cache item will never raise an exception, the
        #  item will just remain uncached.
        # @return [Object]
        #
        def using(options = {})
          merged = Ramaze::Cache::Sequel.trait[:default].merge(options)
          Class.new(self) { @options = merged }
        end
      end

      ##
      # Creates a new instance of the cache class.
      #
      # @author Michael Fellinger
      # @since  04-05-2011
      # @param  [Hash] options A hash with custom options, see
      #  Ramaze::Cache::Sequel.using for all available options.
      #
      def initialize(options = {})
        self.class.options ||= Ramaze::Cache::Sequel.trait[:default].merge(
          options
        )

        @options = options.merge(self.class.options)
      end

      ##
      # Executed after #initialize and before any other method.
      #
      # Some parameters identifying the current process will be passed so caches
      # that act in one global name-space can use them as a prefix.
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [String] hostname  the hostname of the machine
      # @param  [String] username  user executing the process
      # @param  [String] appname   identifier for the application
      # @param  [String] cachename namespace, like 'session' or 'action'
      #
      def cache_setup(hostname, username, appname, cachename)
        @namespace = [hostname, username, appname, cachename].compact.join(':')

        # Create the table if it's not there yet
        if !options[:connection].table_exists?(options[:table])
          options[:connection].create_table(
            options[:table]) do
            primary_key :id
            String :key  , :null => false, :unique => true
            String :value, :text => true
            Time :expires
          end
        end

        @dataset = options[:connection][options[:table].to_sym]
      end

      ##
      # Remove all key/value pairs from the cache. Should behave as if #delete
      # had been called with all +keys+ as argument.
      #
      # @author Lars Olsson
      # @since  18-04-2011
      #
      def cache_clear
        @dataset.delete
      end

      ##
      # Remove the corresponding key/value pair for each key passed. If removing
      # is not an option it should set the corresponding value to nil.
      #
      # If only one key was deleted, answer with the corresponding value. If
      # multiple keys were deleted, answer with an Array containing the values.
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [Object] key The key for the value to delete
      # @param  [Object] keys Any other keys to delete as well
      # @return [Object/Array/nil]
      #
      def cache_delete(key, *keys)
        # Remove a single key
        if keys.empty?
          nkey   = namespaced(key)
          result = @dataset.select(:value).filter(:key => nkey).limit(1)

          # Ramaze expects nil values
          if result.empty?
            result = nil
          else
            result = deserialize(result.first[:value])
          end

          @dataset.filter(:key => nkey).delete
        # Remove multiple keys
        else
          nkeys  = [key, keys].flatten.map! { |n| namespaced(n) }
          result = dataset.select(:value).filter(:key => nkeys)

          result.map! do |row|
            deserialize(row[:value])
          end

          @dataset.filter(:key => nkeys).delete
        end

        return result
      end

      ##
      # Answer with the value associated with the +key+, +nil+ if not found or
      # expired.
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [Object] key The key for which to fetch the value
      # @param  [Object] default Will return this if no value was found
      # @return [Object]
      #
      def cache_fetch(key, default = nil)
        nkey = namespaced(key)

        # Delete expired rows
        @dataset.select.filter(:key => nkey) do
          expires < Time.now
        end.delete

        # Get remaining row (if any)
        result = @dataset.select(:value).filter(:key => nkey).limit(1)

        if result.empty?
          return default
        else
          return deserialize(result.first[:value])
        end
      end

      ##
      # Sets the given key to the given value.
      #
      # @example
      #  Cache.value.store(:num, 3, :ttl => 20)
      #  Cache.value.fetch(:num)
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [Object] key The value is stored with this key
      # @param  [Object] value The key points to this value
      # @param  [Hash] options for now, only :ttl => Fixnum is used.
      # @option options [Fixnum] :ttl The time in seconds after which the cache
      #  item should be expired.
      #
      def cache_store(key, value, options = {})
        nkey = namespaced(key)

        # Get the time after which the cache should be expired
        if options[:ttl]
          ttl = options[:ttl]
        else
          ttl = Ramaze::Cache::Sequel.options[:ttl]
        end

        expires = Time.now + ttl if ttl

        # The row already exists, update it.
        if @dataset.filter(:key => nkey).count == 1
          serialized_value = serialize(value)

          if serialized_value
            @dataset.filter(:key => nkey) \
              .update(:value => serialize(value), :expires => expires)
          end
        # The row doesn't exist yet.
        else
          serialized_value = serialize(value)

          if serialized_value
            @dataset.insert(
              :key => nkey, :value => serialize(value), :expires => expires
            )
          end
        end

        # Try to deserialize the value. If this fails we'll return a different
        # value
        deserialized = deserialize(@dataset.select(:value) \
          .filter(:key => nkey) \
          .limit(1).first[:value])

        if deserialized
          return deserialized
        else
          return value
        end
      end

      ##
      # Prefixes the given key with current namespace.
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [Object] key Key without namespace.
      # @return [Object]
      #
      def namespaced(key)
        return [@namespace, key].join(':')
      end

      ##
      # Deserialize method, adapted from Sequels serialize plugin
      # This method will try to deserialize a value using Marshal.load
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [Object] value Value to be deserialized
      # @return [Object nil]
      #
      def deserialize(value)
        begin
          ::Marshal.load(value.unpack('m')[0])
        rescue
          begin
            ::Marshal.load(value)
          rescue
            # Log the error?
            if options[:display_warnings] === true
              Ramaze::Log::warn("Failed to deserialize #{value.inspect}")
            end

            return nil
          end
        end
      end

      ##
      # Serialize method, adapted from Sequels serialize plugin
      # This method will try to serialize a value using Marshal.dump
      #
      # @author Lars Olsson
      # @since  18-04-2011
      # @param  [Object] value Value to be serialized.
      # @return [Object nil]
      #
      def serialize(value)
        begin
          [::Marshal.dump(value)].pack('m')
        rescue
          if options[:display_warnings] === true
            Ramaze::Log::warn("Failed to serialize #{value.inspect}")
          end

          return nil
        end
      end
    end # Sequel
  end # Cache
end # Ramaze