File: file.rb

package info (click to toggle)
ruby-moneta 1.6.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,776 kB
  • sloc: ruby: 13,201; sh: 178; makefile: 7
file content (135 lines) | stat: -rw-r--r-- 3,735 bytes parent folder | download | duplicates (2)
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
require 'fileutils'
require 'English'

module Moneta
  module Adapters
    # Filesystem backend
    # @api public
    class File
      include Defaults
      include Config

      supports :create, :increment, :each_key

      config :dir, required: true

      # @param [Hash] options
      # @option options [String] :dir Directory where files will be stored
      def initialize(options = {})
        configure(**options)
        FileUtils.mkpath(config.dir)
        raise "#{config.dir} is not a directory" unless ::File.directory?(config.dir)
      end

      # (see Proxy#key?)
      def key?(key, options = {})
        ::File.exist?(store_path(key))
      end

      # (see Proxy#each_key)
      def each_key(&block)
        entries = ::Dir.entries(config.dir).reject do |k|
          ::File.directory?(::File.join(config.dir, k))
        end

        if block_given?
          entries.each { |k| yield(k) }
          self
        else
          enum_for(:each_key) { ::Dir.entries(config.dir).length - 2 }
        end
      end

      # (see Proxy#load)
      def load(key, options = {})
        ::File.read(store_path(key), mode: 'rb')
      rescue Errno::ENOENT
        nil
      end

      # (see Proxy#store)
      def store(key, value, options = {})
        temp_file = ::File.join(config.dir, "value-#{$PROCESS_ID}-#{Thread.current.object_id}")
        path = store_path(key)
        FileUtils.mkpath(::File.dirname(path))
        ::File.open(temp_file, 'wb') { |f| f.write(value) }
        ::File.rename(temp_file, path)
        value
      rescue
        File.unlink(temp_file) rescue nil
        raise
      end

      # (see Proxy#delete)
      def delete(key, options = {})
        value = load(key, options)
        ::File.unlink(store_path(key))
        value
      rescue Errno::ENOENT
        nil
      end

      # (see Proxy#clear)
      def clear(options = {})
        temp_dir = "#{config.dir}-#{$PROCESS_ID}-#{Thread.current.object_id}"
        ::File.rename(config.dir, temp_dir)
        FileUtils.mkpath(config.dir)
        self
      rescue Errno::ENOENT
        self
      ensure
        FileUtils.rm_rf(temp_dir)
      end

      # (see Proxy#increment)
      def increment(key, amount = 1, options = {})
        path = store_path(key)
        FileUtils.mkpath(::File.dirname(path))
        ::File.open(path, ::File::RDWR | ::File::CREAT) do |f|
          Thread.pass until f.flock(::File::LOCK_EX)
          content = f.read
          amount += Integer(content) unless content.empty?
          content = amount.to_s
          f.binmode
          f.pos = 0
          f.write(content)
          f.truncate(content.bytesize)
          amount
        end
      end

      # HACK: The implementation using File::EXCL is not atomic under JRuby 1.7.4
      # See https://github.com/jruby/jruby/issues/827
      if defined?(JRUBY_VERSION)
        # (see Proxy#create)
        def create(key, value, options = {})
          path = store_path(key)
          FileUtils.mkpath(::File.dirname(path))
          # Call native java.io.File#createNewFile
          return false unless ::Java::JavaIo::File.new(path).createNewFile
          ::File.open(path, 'wb+') { |f| f.write(value) }
          true
        end
      else
        # (see Proxy#create)
        def create(key, value, options = {})
          path = store_path(key)
          FileUtils.mkpath(::File.dirname(path))
          ::File.open(path, ::File::WRONLY | ::File::CREAT | ::File::EXCL) do |f|
            f.binmode
            f.write(value)
          end
          true
        rescue Errno::EEXIST
          false
        end
      end

      protected

      def store_path(key)
        ::File.join(config.dir, key)
      end
    end
  end
end