Class: Saviour::File

Inherits:
Object
  • Object
show all
Defined in:
lib/saviour/file.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uploader_klass, model, attached_as) ⇒ File

Returns a new instance of File.



8
9
10
11
# File 'lib/saviour/file.rb', line 8

def initialize(uploader_klass, model, attached_as)
  @uploader_klass, @model, @attached_as = uploader_klass, model, attached_as
  @source_was = @source = nil
end

Instance Attribute Details

#persisted_pathObject (readonly)

Returns the value of attribute persisted_path.



5
6
7
# File 'lib/saviour/file.rb', line 5

def persisted_path
  @persisted_path
end

#sourceObject (readonly)

Returns the value of attribute source.



6
7
8
# File 'lib/saviour/file.rb', line 6

def source
  @source
end

Instance Method Details

#==(another_file) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'lib/saviour/file.rb', line 38

def ==(another_file)
  return false unless another_file.is_a?(Saviour::File)
  return false unless another_file.persisted? == persisted?

  if persisted?
    another_file.persisted_path == persisted_path
  else
    another_file.source == @source
  end
end

#__maybe_with_tmpfile(source_type, file) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/saviour/file.rb', line 128

def __maybe_with_tmpfile(source_type, file)
  return yield if source_type == :stream

  tmpfile = Tempfile.new([::File.basename(file.path, ".*"), ::File.extname(file.path)])
  tmpfile.binmode
  FileUtils.cp(file.path, tmpfile.path)

  begin
    yield(tmpfile)
  ensure
    tmpfile.close!
  end
end

#assign(object) ⇒ Object

Raises:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/saviour/file.rb', line 75

def assign(object)
  raise(SourceError, "given object to #assign or #<attach_as>= must respond to `read`") if object && !object.respond_to?(:read)

  followers = @model.class.followers_per_leader_config[@attached_as]

  (followers || []).each do |x|
    attachment = @model.send(x[:attachment])
    attachment.assign(object) unless attachment.changed?
  end

  @source_data = nil
  @source = object

  if changed? && @model.respond_to?("#{@attached_as}_will_change!")
    @model.send "#{@attached_as}_will_change!"
  end

  @persisted_path = nil if object

  object
end

#blank?Boolean

Returns:

  • (Boolean)


185
186
187
# File 'lib/saviour/file.rb', line 185

def blank?
  !@source && !persisted?
end

#changed?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/saviour/file.rb', line 101

def changed?
  @source_was != @source
end

#cloneObject



49
50
51
52
53
54
55
# File 'lib/saviour/file.rb', line 49

def clone
  return nil unless persisted?

  new_file = Saviour::File.new(@uploader_klass, @model, @attached_as)
  new_file.set_path! @persisted_path
  new_file
end

#deleteObject



26
27
28
29
30
31
# File 'lib/saviour/file.rb', line 26

def delete
  persisted? && Config.storage.delete(@persisted_path)
  @persisted_path = nil
  @source_was = nil
  @source = nil
end

#dup(new_model) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/saviour/file.rb', line 57

def dup(new_model)
  new_file = Saviour::File.new(@uploader_klass, new_model, @attached_as)

  if persisted?
    new_file.assign(Saviour::StringSource.new(read, filename))
  elsif @source
    new_file.assign(Saviour::StringSource.new(source_data, filename_to_be_assigned))
  end

  new_file
end

#exists?Boolean

Returns:

  • (Boolean)


17
18
19
# File 'lib/saviour/file.rb', line 17

def exists?
  persisted? && Config.storage.exists?(@persisted_path)
end

#filenameObject



105
106
107
# File 'lib/saviour/file.rb', line 105

def filename
  ::File.basename(@persisted_path) if persisted?
end

#filename_to_be_assignedObject



124
125
126
# File 'lib/saviour/file.rb', line 124

def filename_to_be_assigned
  changed? ? (SourceFilenameExtractor.new(@source).detected_filename || SecureRandom.hex) : nil
end

#persisted?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/saviour/file.rb', line 97

def persisted?
  !!@persisted_path
end

#public_urlObject Also known as: url



33
34
35
36
# File 'lib/saviour/file.rb', line 33

def public_url
  return nil unless persisted?
  Config.storage.public_url(@persisted_path)
end

#readObject



21
22
23
24
# File 'lib/saviour/file.rb', line 21

def read
  return nil unless persisted?
  Config.storage.read(@persisted_path)
end

#reloadObject



69
70
71
# File 'lib/saviour/file.rb', line 69

def reload
  @model.instance_variable_set("@__uploader_#{@attached_as}", nil)
end

#set_path!(path) ⇒ Object



13
14
15
# File 'lib/saviour/file.rb', line 13

def set_path!(path)
  @persisted_path = path
end

#source_dataObject



178
179
180
181
182
183
# File 'lib/saviour/file.rb', line 178

def source_data
  @source_data ||= begin
    @source.rewind
    @source.read
  end
end

#source_typeObject



170
171
172
173
174
175
176
# File 'lib/saviour/file.rb', line 170

def source_type
  if @source.respond_to?(:path)
    :file
  else
    :stream
  end
end

#uploaderObject



189
190
191
# File 'lib/saviour/file.rb', line 189

def uploader
  @uploader ||= @uploader_klass.new(data: { model: @model, attached_as: @attached_as })
end

#with_copyObject

Raises:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/saviour/file.rb', line 109

def with_copy
  raise CannotCopy, "must be persisted" unless persisted?

  temp_file = Tempfile.new([::File.basename(filename, ".*"), ::File.extname(filename)])
  temp_file.binmode

  begin
    Config.storage.read_to_file(@persisted_path, temp_file)

    yield(temp_file)
  ensure
    temp_file.close!
  end
end

#write(before_write: nil) ⇒ Object

Raises:



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
# File 'lib/saviour/file.rb', line 142

def write(before_write: nil)
  raise(MissingSource, "You must provide a source to read from before trying to write") unless @source

  __maybe_with_tmpfile(source_type, @source) do |tmpfile|
    contents, path = case source_type
                       when :stream
                         uploader._process_as_contents(source_data, filename_to_be_assigned)
                       when :file
                         uploader._process_as_file(tmpfile, filename_to_be_assigned)
                     end
    @source_was = @source

    if path
      before_write.call(path) if before_write

      case source_type
        when :stream
          Config.storage.write(contents, path)
        when :file
          Config.storage.write_from_file(contents, path)
      end

      @persisted_path = path
      path
    end
  end
end