sga_paperclippolymorph 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 tim.teng
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = sga_paperclippolymorph
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 tim.teng. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "sga_paperclippolymorph"
8
+ gem.summary = %Q{gem version of paperclippolymorph for sga company}
9
+ gem.description = %Q{gem version of paperclippolymorph for sga company}
10
+ gem.email = "tim.rubist@gmail.com"
11
+ gem.homepage = "http://github.com/tteng/sga_paperclippolymorph"
12
+ gem.authors = ["tim.teng"]
13
+ #gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_runtime_dependency "paperclip", ">= 2.3.1.1"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "sga_paperclippolymorph #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,8 @@
1
+ Description:
2
+ This generator creates the migrations needed to use polymorphic paperclip
3
+
4
+ Example:
5
+ ./script/generate polymorphic_paperclip
6
+
7
+ This will create:
8
+ - A migration, which adds an assets and attachings table.
@@ -0,0 +1,52 @@
1
+ class PolymorphicPaperclipGenerator < Rails::Generator::Base
2
+ def initialize(runtime_args, runtime_options = {})
3
+ super
4
+ end
5
+
6
+ def manifest
7
+ recorded_session = record do |m|
8
+
9
+ unless has_rspec?
10
+ puts " All test for PolymorphicPaperclip are written in rSpec."
11
+ puts " Consider installing rSpec and the rSpec on rails plugin."
12
+ end
13
+
14
+ unless options[:skip_migration]
15
+ m.migration_template 'migration.rb', 'db/migrate',
16
+ :assigns => { :migration_name => "PolymorphicPaperclipMigration" },
17
+ :migration_file_name => "polymorphic_paperclip_migration"
18
+ end
19
+ end
20
+
21
+ action = nil
22
+ action = $0.split("/")[1]
23
+ case action
24
+ when "generate"
25
+ puts
26
+ puts ("-" * 70)
27
+ puts "Success!"
28
+ puts
29
+ puts "Dont't Forget to:"
30
+ puts " - Add the acts_as_polymorphic_paperclip to the model that accepts assets"
31
+ puts " You will no longer need the has_attached_file argument in your model once you"
32
+ puts " add this plugin."
33
+ puts
34
+ unless options[:skip_migration]
35
+ puts " - Run the migration."
36
+ puts " rake db:migrate"
37
+ end
38
+ puts
39
+ puts
40
+ puts ("-" * 70)
41
+ puts
42
+ else
43
+ puts
44
+ end
45
+
46
+ recorded_session end
47
+
48
+ def has_rspec?
49
+ options[:rspec] || (File.exist?('spec') && File.directory?('spec'))
50
+ end
51
+
52
+ end
@@ -0,0 +1,28 @@
1
+ class <%= migration_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "assets" do |t|
4
+ t.string "data_file_name"
5
+ t.string "data_content_type"
6
+ t.integer "data_file_size"
7
+ t.integer "attachings_count", :default => 0
8
+ t.datetime "created_at"
9
+ t.datetime "data_updated_at"
10
+ end
11
+
12
+ create_table "attachings" do |t|
13
+ t.integer "attachable_id"
14
+ t.integer "asset_id"
15
+ t.string "attachable_type"
16
+ t.datetime "created_at"
17
+ t.datetime "updated_at"
18
+ end
19
+
20
+ add_index "attachings", ["asset_id"], :name => "index_attachings_on_asset_id"
21
+ add_index "attachings", ["attachable_id"], :name => "index_attachings_on_attachable_id"
22
+ end
23
+
24
+ def self.down
25
+ drop_table :assets
26
+ drop_table :attachings
27
+ end
28
+ end
@@ -0,0 +1,113 @@
1
+ module LocusFocus
2
+ module Acts #:nodoc: all
3
+ module PolymorphicPaperclip
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ # Extends the model to afford the ability to associate other records with the receiving record.
10
+ #
11
+ # This module needs the paperclip plugin to work
12
+ # http://www.thoughtbot.com/projects/paperclip
13
+ def acts_as_polymorphic_paperclip(options = {})
14
+ write_inheritable_attribute(:acts_as_polymorphic_paperclip_options, {
15
+ :counter_cache => options[:counter_cache],
16
+ :styles => options[:styles]
17
+ })
18
+ class_inheritable_reader :acts_as_polymorphic_paperclip_options
19
+
20
+ has_many :attachings, :as => :attachable, :dependent => :destroy
21
+ has_many :assets, :through => :attachings do
22
+ def attach(asset_id)
23
+ asset_id = extract_id(asset_id)
24
+ asset = Asset.find(asset_id)
25
+ @owner.assets << asset
26
+ @owner.assets(true)
27
+ end
28
+
29
+ def detach(asset_id, delete_if_no_attachings = false)
30
+ asset_id = extract_id(asset_id)
31
+ attaching = @owner.attachings.find(:first, :conditions => ['asset_id = ?', asset_id])
32
+ attachable = attaching.attachable
33
+ raise ActiveRecord::RecordNotFound unless attaching
34
+ result = attaching.destroy
35
+
36
+ asset = Asset.find(asset_id)
37
+ if asset.attachings.empty? && delete_if_no_attachings# delete if no longer attached to anything
38
+ override_default_styles, normalised_styles = attachable.override_default_styles?(asset.name)
39
+ asset.data.instance_variable_set("@styles", normalised_styles) if override_default_styles
40
+ asset.data.send(:queue_existing_for_delete)
41
+ asset.data.send(:flush_deletes)
42
+ asset.save # needed to permanently remove file name and urls
43
+ end
44
+ result
45
+ end
46
+
47
+ protected
48
+ def extract_id(obj)
49
+ return obj.id unless obj.class == Fixnum || obj.class == String
50
+ obj.to_i if obj.to_i > 0
51
+ end
52
+ end
53
+
54
+ # Virtual attribute for the ActionController::UploadedStringIO
55
+ # which consists of these attributes "content_type", "original_filename" & "original_path"
56
+ # content_type: image/png
57
+ # original_filename: 64x16.png
58
+ # original_path: 64x16.png
59
+ attr_accessor :data
60
+
61
+ include LocusFocus::Acts::PolymorphicPaperclip::InstanceMethods
62
+ end
63
+ end
64
+ module InstanceMethods
65
+ def after_save
66
+ super
67
+ Asset.transaction do
68
+ if data.is_a?(Array)
69
+ data.each do |data_item|
70
+ create_and_save_asset(data_item) unless data_item.nil? || data_item.blank?
71
+ end
72
+ else
73
+ create_and_save_asset(data)
74
+ end
75
+ end unless data.nil? || data.blank?
76
+ end
77
+
78
+ def create_and_save_asset(data_item)
79
+ the_asset = Asset.find_or_initialize_by_data_file_name(data_item.original_filename)
80
+ override_default_styles, normalised_styles = override_default_styles?(data_item.original_filename)
81
+ the_asset.data.instance_variable_set("@styles", normalised_styles) if override_default_styles
82
+ the_asset.data = data_item
83
+ if the_asset.save
84
+
85
+ # This association may be saved more than once within the same request / response
86
+ # cycle, which leads to needless DB calls. Now we'll clear out the data attribute
87
+ # once the record is successfully saved any subsequent calls will be ignored.
88
+ data_item = nil
89
+ Attaching.find_or_create_by_asset_id_and_attachable_type_and_attachable_id(:asset_id => the_asset.id, :attachable_type => self.class.to_s, :attachable_id => self.id)
90
+ assets(true) # implicit reloading
91
+ end
92
+ end
93
+ def override_default_styles?(filename)
94
+ if !acts_as_polymorphic_paperclip_options[:styles].nil?
95
+ normalised_styles = {}
96
+ acts_as_polymorphic_paperclip_options[:styles].each do |name, args|
97
+ dimensions, format = [args, nil].flatten[0..1]
98
+ format = nil if format.blank?
99
+ if filename.match(/\.pdf$/) # remove crop commands if file is a PDF (this fails with Imagemagick)
100
+ args.gsub!(/#/ , "")
101
+ format = "png"
102
+ end
103
+ normalised_styles[name] = { :processors => [:thumbnail], :geometry => dimensions, :format => format }
104
+ end
105
+ return true, normalised_styles
106
+ else
107
+ return false
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
data/lib/sga/asset.rb ADDED
@@ -0,0 +1,67 @@
1
+ gem 'paperclip', ">=2.3.1.1"
2
+ require 'paperclip'
3
+ require 'digest/md5'
4
+
5
+ class Asset < ActiveRecord::Base
6
+ has_many :attachings, :dependent => :destroy
7
+
8
+ has_attached_file :data,
9
+ :styles => {
10
+ :tiny => "64x64>",
11
+ :small => "176x112>",
12
+ :medium => "630x630>",
13
+ :large => "1024x1024>"
14
+ }
15
+
16
+ def url(*args)
17
+ data.url(*args)
18
+ end
19
+
20
+ def name
21
+ data_file_name
22
+ end
23
+
24
+ def content_type
25
+ data_content_type
26
+ end
27
+
28
+ def browser_safe?
29
+ %w(jpg gif png).include?(url.split('.').last.sub(/\?.+/, "").downcase)
30
+ end
31
+ alias_method :web_safe?, :browser_safe?
32
+
33
+ # This method will replace one of the existing thumbnails with an file provided.
34
+ def replace_style(style, file)
35
+ style = style.downcase.to_sym
36
+ if data.styles.keys.include?(style)
37
+ if File.exist?(RAILS_ROOT + '/public' + a.data(style))
38
+ end
39
+ end
40
+ end
41
+
42
+ # This method assumes you have images that corespond to the filetypes.
43
+ # For example "image/png" becomes "image-png.png"
44
+ def icon
45
+ "#{data_content_type.gsub(/[\/\.]/,'-')}.png"
46
+ end
47
+
48
+ def detach(attached)
49
+ a = attachings.find(:first, :conditions => ["attachable_id = ? AND attachable_type = ?", attached, attached.class.to_s])
50
+ raise ActiveRecord::RecordNotFound unless a
51
+ a.destroy
52
+ end
53
+
54
+ def path
55
+ File.join RAILS_ROOT, 'public', self.url_without_random
56
+ end
57
+
58
+ def file_md5sum
59
+ #path = File.join RAILS_ROOT, 'public', self.url_without_random
60
+ IO.popen("md5sum #{path} | awk '{print $1}'"){|f| f.gets.strip}
61
+ end
62
+
63
+ def url_without_random format=:original
64
+ self.url(format) =~ /^(.*)\?\d*$/ ? $1 : self.url(format)
65
+ end
66
+
67
+ end
@@ -0,0 +1,16 @@
1
+ class Attaching < ActiveRecord::Base
2
+ belongs_to :asset, :counter_cache => true
3
+ belongs_to :attachable, :polymorphic => true
4
+
5
+ def after_create
6
+ if self.attachable.acts_as_polymorphic_paperclip_options[:counter_cache]
7
+ self.attachable.class.increment_counter(:assets_count, self.attachable.id)
8
+ end
9
+ end
10
+
11
+ def after_destroy
12
+ if self.attachable.acts_as_polymorphic_paperclip_options[:counter_cache]
13
+ self.attachable.class.decrement_counter(:assets_count, self.attachable.id)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ require 'sga/acts_as_polymorphic_paperclip'
2
+ ActiveRecord::Base.send(:include, LocusFocus::Acts::PolymorphicPaperclip)
3
+ require 'sga/asset'
4
+ require 'sga/attaching'
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'sga_paperclippolymorph'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestSgaPaperclippolymorph < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sga_paperclippolymorph
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - tim.teng
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-07 00:00:00 +08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: paperclip
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 1
31
+ - 1
32
+ version: 2.3.1.1
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: gem version of paperclippolymorph for sga company
36
+ email: tim.rubist@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION
51
+ - generators/polymorphic_paperclip/USAGE
52
+ - generators/polymorphic_paperclip/polymorphic_paperclip_generator.rb
53
+ - generators/polymorphic_paperclip/templates/migration.rb
54
+ - lib/sga/acts_as_polymorphic_paperclip.rb
55
+ - lib/sga/asset.rb
56
+ - lib/sga/attaching.rb
57
+ - lib/sga_paperclippolymorph.rb
58
+ - test/helper.rb
59
+ - test/test_sga_paperclippolymorph.rb
60
+ has_rdoc: true
61
+ homepage: http://github.com/tteng/sga_paperclippolymorph
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --charset=UTF-8
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.6
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: gem version of paperclippolymorph for sga company
90
+ test_files:
91
+ - test/test_sga_paperclippolymorph.rb
92
+ - test/helper.rb