Skip to content

Commit

Permalink
Split part of attacher off into AttachmentDefinition
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Apr 21, 2015
1 parent 25c9e58 commit 846dbd8
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 48 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ Style/SignalException:
Style/IndentationWidth:
Enabled: false

Style/TrivialAccessors:
ExactNameMatch: true

Lint/EndAlignment:
AlignWith: variable

Expand Down
1 change: 1 addition & 0 deletions lib/refile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ def valid_token?(path, token)
require "refile/signature"
require "refile/type"
require "refile/backend_macros"
require "refile/attachment_definition"
require "refile/attacher"
require "refile/attachment"
require "refile/random_hasher"
Expand Down
52 changes: 23 additions & 29 deletions lib/refile/attacher.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
module Refile
# @api private
class Attacher
attr_reader :record, :name, :cache, :store, :options, :errors, :type, :valid_extensions, :valid_content_types
attr_reader :definition, :record, :errors
attr_accessor :remove

Presence = ->(val) { val if val != "" }

def initialize(record, name, cache:, store:, raise_errors: true, type: nil, extension: nil, content_type: nil)
def initialize(definition, record)
@definition = definition
@record = record
@name = name
@raise_errors = raise_errors
@cache = Refile.backends.fetch(cache.to_s)
@store = Refile.backends.fetch(store.to_s)
@type = type
@valid_extensions = [extension].flatten if extension
@valid_content_types = [content_type].flatten if content_type
@valid_content_types ||= Refile.types.fetch(type).content_type if type
@errors = []
@metadata = {}
end

def name
@definition.name
end

def cache
@definition.cache
end

def store
@definition.store
end

def id
Presence[read(:id)]
end
Expand Down Expand Up @@ -88,7 +93,7 @@ def cache!(uploadable)
if valid?
@metadata[:id] = cache.upload(uploadable).id
write_metadata
elsif @raise_errors
elsif @definition.raise_errors?
raise Refile::Invalid, @errors.join(", ")
end
end
Expand All @@ -104,13 +109,13 @@ def download(url)
if valid?
@metadata[:id] = cache.upload(response.file).id
write_metadata
elsif @raise_errors
elsif @definition.raise_errors?
raise Refile::Invalid, @errors.join(", ")
end
end
rescue RestClient::Exception
@errors = [:download_failed]
raise if @raise_errors
raise if @definition.raise_errors?
end

def store!
Expand All @@ -132,14 +137,6 @@ def delete!
@metadata = {}
end

def accept
if valid_content_types
valid_content_types.join(",")
elsif valid_extensions
valid_extensions.map { |e| ".#{e}" }.join(",")
end
end

def remove?
remove and remove != "" and remove !~ /\A0|false$\z/
end
Expand All @@ -148,18 +145,15 @@ def present?
not @metadata.empty?
end

def valid?
@errors = []
@errors << :invalid_extension if valid_extensions and not valid_extensions.include?(extension)
@errors << :invalid_content_type if valid_content_types and not valid_content_types.include?(content_type)
@errors << :too_large if cache.max_size and size and size >= cache.max_size
@errors.empty?
end

def data
@metadata if valid?
end

def valid?
@errors = @definition.validate(self)
@errors.empty?
end

private

def read(column)
Expand Down
32 changes: 22 additions & 10 deletions lib/refile/attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,29 @@ module Attachment
# @ignore
# rubocop:disable Metrics/MethodLength
def attachment(name, cache: :cache, store: :store, raise_errors: true, type: nil, extension: nil, content_type: nil)
definition = AttachmentDefinition.new(name,
cache: cache,
store: store,
raise_errors: raise_errors,
type: type,
extension: extension,
content_type: content_type
)

define_singleton_method :"#{name}_attachment_definition" do
definition
end

mod = Module.new do
attacher = :"#{name}_attacher"

define_method :"#{name}_attachment_definition" do
definition
end

define_method attacher do
ivar = :"@#{attacher}"
instance_variable_get(ivar) or begin
instance_variable_set(ivar, Attacher.new(self, name,
cache: cache,
store: store,
raise_errors: raise_errors,
type: type,
extension: extension,
content_type: content_type
))
end
instance_variable_get(ivar) or instance_variable_set(ivar, Attacher.new(definition, self))
end

define_method "#{name}=" do |value|
Expand All @@ -77,6 +85,10 @@ def attachment(name, cache: :cache, store: :store, raise_errors: true, type: nil
define_method "remote_#{name}_url" do
end

define_method "#{name}_data" do
send(attacher).data
end

define_singleton_method("to_s") { "Refile::Attachment(#{name})" }
define_singleton_method("inspect") { "Refile::Attachment(#{name})" }
end
Expand Down
46 changes: 46 additions & 0 deletions lib/refile/attachment_definition.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module Refile
# @api private
class AttachmentDefinition
attr_reader :record, :name, :cache, :store, :options, :type, :valid_extensions, :valid_content_types
attr_accessor :remove

def initialize(name, cache:, store:, raise_errors: true, type: nil, extension: nil, content_type: nil)
@name = name
@raise_errors = raise_errors
@cache_name = cache
@store_name = store
@type = type
@valid_extensions = [extension].flatten if extension
@valid_content_types = [content_type].flatten if content_type
@valid_content_types ||= Refile.types.fetch(type).content_type if type
end

def cache
Refile.backends.fetch(@cache_name.to_s)
end

def store
Refile.backends.fetch(@store_name.to_s)
end

def accept
if valid_content_types
valid_content_types.join(",")
elsif valid_extensions
valid_extensions.map { |e| ".#{e}" }.join(",")
end
end

def raise_errors?
@raise_errors
end

def validate(attacher)
errors = []
errors << :invalid_extension if valid_extensions and not valid_extensions.include?(attacher.extension)
errors << :invalid_content_type if valid_content_types and not valid_content_types.include?(attacher.content_type)
errors << :too_large if cache.max_size and attacher.size and attacher.size >= cache.max_size
errors
end
end
end
12 changes: 6 additions & 6 deletions lib/refile/rails/attachment_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,22 +63,22 @@ def attachment_image_tag(record, name, *args, fallback: nil, format: nil, host:
def attachment_field(object_name, method, object:, **options)
options[:data] ||= {}

attacher = object.send(:"#{method}_attacher")
options[:accept] = attacher.accept
definition = object.send(:"#{method}_attachment_definition")
options[:accept] = definition.accept

if options[:direct]
host = options[:host] || Refile.host || request.base_url
backend_name = Refile.backends.key(attacher.cache)
backend_name = Refile.backends.key(definition.cache)

url = ::File.join(host, main_app.refile_app_path, backend_name)
options[:data].merge!(direct: true, as: "file", url: url)
end

if options[:presigned] and attacher.cache.respond_to?(:presign)
options[:data].merge!(direct: true).merge!(attacher.cache.presign.as_json)
if options[:presigned] and definition.cache.respond_to?(:presign)
options[:data].merge!(direct: true).merge!(definition.cache.presign.as_json)
end

html = hidden_field(object_name, method, value: attacher.data.to_json, object: object, id: nil)
html = hidden_field(object_name, method, value: object.send("#{method}_data").to_json, object: object, id: nil)
html + file_field(object_name, method, options)
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/refile/attachment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -348,20 +348,20 @@
end
end

describe ":name_attacher.accept" do
describe ":name_definition.accept" do
context "with `extension`" do
let(:options) { { extension: %w[jpg png] } }

it "returns an accept string" do
expect(instance.document_attacher.accept).to eq(".jpg,.png")
expect(instance.document_attachment_definition.accept).to eq(".jpg,.png")
end
end

context "with `content_type`" do
let(:options) { { content_type: %w[image/jpeg image/png], extension: "zip" } }

it "returns an accept string" do
expect(instance.document_attacher.accept).to eq("image/jpeg,image/png")
expect(instance.document_attachment_definition.accept).to eq("image/jpeg,image/png")
end
end
end
Expand Down

0 comments on commit 846dbd8

Please sign in to comment.