stash-magic 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +112 -65
- data/spec.rb +5 -0
- data/stash_magic.gemspec +1 -1
- data/stash_magic.rb +3 -3
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
"I switch off the light. Where does it go?" -- Famous Koan
|
2
|
+
|
1
3
|
= Stash Magic (BETA)
|
2
4
|
|
3
5
|
Stash Magic provides a very simple interface for dealing with file system attachments in a database and help you with thumbnails or other styles via ImageMagick (hence, the name). Features are:
|
@@ -9,77 +11,91 @@ Stash Magic provides a very simple interface for dealing with file system attach
|
|
9
11
|
- Easy to understand (one file) module
|
10
12
|
|
11
13
|
This is still in Beta version built with simplicity in mind.
|
14
|
+
It tries to do a lot with less code that anybody would be able to understand quickly.
|
12
15
|
Don't hesitate to contact me for any improvement, suggestion, or bug fixing.
|
13
16
|
|
14
17
|
I've made the design choice not to build a Sequel plugin because I'd like StashMagic to work with other ORMs in the future.
|
18
|
+
I'm pretty sure that if it doesn't already work with ActiveRecord, only changing a couple of names would fix it.
|
15
19
|
So any test or help is welcome.
|
16
20
|
|
21
|
+
= How to install
|
22
|
+
|
23
|
+
gem install stash-magic
|
24
|
+
|
25
|
+
Use Sudo if you want to install it for all users of your server:
|
26
|
+
|
27
|
+
sudo gem install stash-magic
|
28
|
+
|
29
|
+
If you have Ruby 1.9, this is most likely that you have to replace the command gem by gem19:
|
30
|
+
|
31
|
+
sudo gem19 install stash-magic
|
32
|
+
|
17
33
|
= How to use
|
18
34
|
|
19
35
|
First you have to require the module:
|
20
36
|
|
21
|
-
|
22
|
-
|
37
|
+
require 'stash_magic'
|
38
|
+
|
23
39
|
And then inside your model class, you have to include the module and declare where your public directory is:
|
24
40
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
41
|
+
class Treasure < ::Sequel::Model
|
42
|
+
include ::StashMagic
|
43
|
+
self.public_root = ::File.expand_path(::File.dirname(__FILE__)+'/public')
|
44
|
+
end
|
45
|
+
|
30
46
|
The module has a method to do both in one line though:
|
31
47
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
48
|
+
class Treasure < ::Sequel::Model
|
49
|
+
::StashMagic.with_public_root ::File.expand_path(::File.dirname(__FILE__)+'/public')
|
50
|
+
end
|
51
|
+
|
36
52
|
After that, for each attachment you want, you need to have a column in the database as a string. And then you declare them with method Model#stash:
|
37
53
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
54
|
+
class Treasure < ::Sequel::Model
|
55
|
+
::StashMagic.with_public_root ::File.expand_path(::File.dirname(__FILE__)+'/public')
|
56
|
+
|
57
|
+
stash :map
|
58
|
+
stash :stamp
|
59
|
+
end
|
60
|
+
|
45
61
|
This method accepts an optional hash as a second argument which is not used by the module itself, but could be handy for you as you can have it in the stash reflection:
|
46
62
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
class Treasure < ::Sequel::Model
|
64
|
+
::StashMagic.with_public_root ::File.expand_path(::File.dirname(__FILE__)+'/public')
|
65
|
+
|
66
|
+
stash :map
|
67
|
+
stash :stamp, :accept_gif => false, :limit => 512000
|
68
|
+
end
|
69
|
+
|
54
70
|
The method Treasure.stash_reflection would return:
|
55
71
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
72
|
+
{
|
73
|
+
:map => {},
|
74
|
+
:stamp => {:accept_gif => false, :limit => 512000}
|
75
|
+
}
|
76
|
+
|
61
77
|
When building your html forms, just make sure that your stash inputs are of the type 'file', and StashMagic will deal with everything else. The getters will return a hash with the following values:
|
62
78
|
|
63
|
-
|
64
|
-
|
65
|
-
|
79
|
+
@treasure_instance.map # { :name => 'map.pdf', :type => 'application/pdf', :size => 1024 }
|
80
|
+
@treasure_instance.stamp # nil if there is no stamp yet
|
81
|
+
|
66
82
|
Please note that the file name will always be the name of the attachment with the extention of the file you've uploaded (pdf, jpg ...)
|
67
83
|
This makes StashMagic internals a lot easier for dealing with styles (ex: thumbnails) as we'll see later.
|
68
|
-
|
84
|
+
|
69
85
|
You can also use the setters to delete an attachment:
|
70
86
|
|
71
|
-
|
72
|
-
|
87
|
+
@treasure_instance.map = nil # Will delete this attachment as expected
|
88
|
+
|
73
89
|
When you want to use attachment in your application, you can retrieve the file url like that:
|
74
90
|
|
75
|
-
|
76
|
-
|
77
|
-
|
91
|
+
@treasure_instance.file_url(:map) # The original file
|
92
|
+
@treasure_instance.file_url(:map, 'thumb.gif') # The picture in a thumb.gif style (see next chapter to learn about styles)
|
93
|
+
|
78
94
|
You might also want to do things on the server side like changing rights on the image or whatever. For that purpose, there is a third argument which is a boolean. When set to true, it will give you the absolute path to the file:
|
79
95
|
|
80
|
-
|
81
|
-
|
82
|
-
|
96
|
+
@treasure_instance.file_url(:map, nil, true) # /absolute/path/to/public/stash/Treasure/1/map.pdf
|
97
|
+
@treasure_instance.file_url(:map, 'thumb.gif', true) # /absolute/path/to/public/stash/Treasure/1/map.thumb.gif
|
98
|
+
|
83
99
|
= Thumbnails and Other Styles
|
84
100
|
|
85
101
|
One of the main requirements of StashMagic was to provide a way to deal quite easily with styles, and to deal with them whenever you want to, not only automaticaly when you save an attachment. The reason for that last point is because I was working at the same time on a cropping tool and realized That I needed to be able to create styles whenever I wanted without changing the way my attachment manager works.
|
@@ -88,8 +104,8 @@ The simpliest solution I came up with was to be quite strict with names. So far,
|
|
88
104
|
|
89
105
|
Say for example you have an attachment called :portrait and you want a version called "mini" which is gonna be a gif. Your style should be called:
|
90
106
|
|
91
|
-
|
92
|
-
|
107
|
+
mini.gif
|
108
|
+
|
93
109
|
I just find it makes sense and saves one argument on some methods that are already verbose.
|
94
110
|
|
95
111
|
Now if you really want to create styles, you need to have ImageMagick installed. ImageMagick is a very good and complete graphic library. You'll find more on the link below, but for the time being, just think of it as a Photoshop in command line:
|
@@ -105,8 +121,8 @@ Even though StashMagic provides a builder for ImageMagick scripts, I suggest you
|
|
105
121
|
|
106
122
|
So for the couragous amongst you, here is the way you create a very simple style for the portrait attachment:
|
107
123
|
|
108
|
-
|
109
|
-
|
124
|
+
@treasure_instance.convert :portrait, '-resize 100x75', 'mini.gif'
|
125
|
+
|
110
126
|
The middle argument is the piece of script used in the main ImageMagick command called: convert
|
111
127
|
It is everything that happens between the source and the destination (hence its position in the list of arguments).
|
112
128
|
|
@@ -116,10 +132,10 @@ This will create your mini version of the portrait. The url for this image will
|
|
116
132
|
|
117
133
|
If you master ImageMagick, you can really do a lot with that. Nevertheless here is what you can use, as I have to admit that some things like geometry are not easy to get the first time. Here is the so-called string builder:
|
118
134
|
|
119
|
-
|
135
|
+
@treasure_instance.image_magick :portrait, 'mini.gif' do
|
120
136
|
im_resize(100, 75)
|
121
|
-
|
122
|
-
|
137
|
+
end
|
138
|
+
|
123
139
|
Not really much easier huh ?!?
|
124
140
|
|
125
141
|
Ok so in the builder, you can use some pre-defined operations (prefixed with 'im_' standing for ImageMagick) that will occur in the order you write them. It is quite limited for the moment, but I will complete the list in time. Here is that list:
|
@@ -128,7 +144,7 @@ Ok so in the builder, you can use some pre-defined operations (prefixed with 'im
|
|
128
144
|
|
129
145
|
This is the most simple one. It is for when you know how to write a piece of the script. For example you could use:
|
130
146
|
|
131
|
-
|
147
|
+
im_write("-negate")
|
132
148
|
|
133
149
|
It will negate the image at this stage.
|
134
150
|
|
@@ -164,35 +180,65 @@ Simply negate the image
|
|
164
180
|
|
165
181
|
Here a more complete example for the builder:
|
166
182
|
|
167
|
-
|
168
|
-
|
183
|
+
@treasure_instance.image_magick :portrait, 'mini.gif' do
|
184
|
+
im_negate
|
169
185
|
im_crop(200,100,20,10)
|
170
186
|
im_resize(200, 100, '^', 'North')
|
171
|
-
|
172
|
-
|
187
|
+
end
|
188
|
+
|
173
189
|
Which will secretly do something like:
|
174
190
|
|
175
|
-
|
176
|
-
|
191
|
+
convert /path/to/portrait.jpg -negate -crop 200x100+20+10 +repage -resize '200x100^' -gravity North -extent 200x100 /path/to/portrait.mini.gif
|
192
|
+
|
177
193
|
= How to create thumbnails on the flight (The Hook)
|
178
194
|
|
179
195
|
It is of course possible. StashMagic provides a hook called after_stash which takes the attachment_name as an argument. This hook is implemented by default and create automaticaly for every image a thumbnail called 'stash_thumb.gif'.
|
180
196
|
|
181
197
|
What you have to do is overwrite the hook. For example, say you want every attachment to have a 200x200 perfect squared version:
|
182
198
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
199
|
+
after_stash(attachment_name)
|
200
|
+
image_magick(attachment_name, 'square.jpg') { im_resize(200, 200, '^') }
|
201
|
+
end
|
202
|
+
|
187
203
|
Of course you can do something different for any attachment. You just need to use the attachment name in a case statement for example. Or you can do something different depending on the type of file using the getters. For example:
|
188
204
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
205
|
+
after_stash(attachment_name)
|
206
|
+
attachment_hash = self.send(attachment_name)
|
207
|
+
image_magick(attachment_name, 'square.jpg') { im_resize(200, 200, '^') } if attachment_hash[:type][/^image\//]
|
208
|
+
end
|
209
|
+
|
194
210
|
Will do the same but only if the mime type of the file starts with 'image/' (which means it's an image).
|
195
211
|
|
212
|
+
= How my files are then saved on my file system
|
213
|
+
|
214
|
+
I like to believe that one don't have to think about that as long as the module provides enough methods to do what you need to do.
|
215
|
+
Nevertheless, here is how files are organized:
|
216
|
+
|
217
|
+
First of all, StashMagic puts everything it has in a folder called 'stash', so that if you use a deployment system, only one location is not to deploy on the live version. For example, while using Git, your .gitignore would have this line:
|
218
|
+
|
219
|
+
public/stash/*
|
220
|
+
|
221
|
+
After that, you've got one folder per model class. And inside this folder, one folder per entry simply named after its ID number. At the end point, you have the attachments, named after the attachment name, and the extention is the original extention if that is the main file, or the style name if this is a style. Here is an example:
|
222
|
+
|
223
|
+
|
|
224
|
+
+- public
|
225
|
+
+- stash
|
226
|
+
+- Treasure
|
227
|
+
+- 1
|
228
|
+
| +- map.jpg
|
229
|
+
| +- map.mini.gif
|
230
|
+
| +- instructions.pdf
|
231
|
+
| \- instructions.cover.jpg
|
232
|
+
\- 2
|
233
|
+
+- map.jpg
|
234
|
+
+- map.mini.gif
|
235
|
+
+- instructions.pdf
|
236
|
+
\- instructions.cover.jpg
|
237
|
+
|
238
|
+
Please note that the class name is a simple #to_s. I've realized recently that methods like underscore or pluralize are computing for nothing in 99% of cases. I might consider them better when they will be in the Standard library. But as a side effect, try to avoid class names that are spelled the same once lowercased, as systems (at least unix based) are not case sensitive. I can give you an example straight away:
|
239
|
+
|
240
|
+
BootStrap
|
241
|
+
BootsTrap
|
196
242
|
|
197
243
|
= More Details
|
198
244
|
|
@@ -207,6 +253,7 @@ The project is speced with
|
|
207
253
|
|
208
254
|
- 0.0.1 Begins
|
209
255
|
- 0.0.2 Add im_negate to the ImageMagick builder
|
256
|
+
- 0.0.3 Fix image destruction when there is nothing to destroy
|
210
257
|
|
211
258
|
== Copyright
|
212
259
|
|
data/spec.rb
CHANGED
@@ -199,6 +199,11 @@ describe ::StashMagic do
|
|
199
199
|
F.exists?(Treasure::PUBLIC+'/stash/Treasure/'+@t.id.to_s+'/instructions.pdf').should==true
|
200
200
|
end
|
201
201
|
|
202
|
+
it "Should not raise when the setter tries to destroy files when there is nothing to destroy" do
|
203
|
+
lambda { @t = Treasure.create(:instructions=>nil) }.should.not.raise
|
204
|
+
lambda { @t.update(:instructions=>nil) }.should.not.raise
|
205
|
+
end
|
206
|
+
|
202
207
|
it "Should have ImageMagick string builder" do
|
203
208
|
@t = Treasure.create(:map=>@img)
|
204
209
|
|
data/stash_magic.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'stash-magic'
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.3"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.summary = "Simple Attachment Manager"
|
6
6
|
s.description = "A simple attachment system that also handles thumbnails or other styles via ImageMagick. Originaly tested on Sequel ORM but purposedly easy to plug to something else."
|
data/stash_magic.rb
CHANGED
@@ -33,12 +33,12 @@ module StashMagic
|
|
33
33
|
# :name=>"model[attachment]"
|
34
34
|
# }
|
35
35
|
#
|
36
|
-
#
|
36
|
+
# SETTER
|
37
37
|
define_method name.to_s+'=' do |upload_hash|
|
38
38
|
return if upload_hash=="" # File in the form is unchanged
|
39
39
|
|
40
40
|
if upload_hash.nil?
|
41
|
-
destroy_files_for(name)
|
41
|
+
destroy_files_for(name) unless self.send(name).nil?
|
42
42
|
super('')
|
43
43
|
else
|
44
44
|
|
@@ -53,7 +53,7 @@ module StashMagic
|
|
53
53
|
|
54
54
|
end
|
55
55
|
end
|
56
|
-
#
|
56
|
+
# GETTER
|
57
57
|
define_method name.to_s do
|
58
58
|
eval(super.to_s)
|
59
59
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stash-magic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mickael Riga
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-12-08 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|