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.
Files changed (5) hide show
  1. data/README.rdoc +112 -65
  2. data/spec.rb +5 -0
  3. data/stash_magic.gemspec +1 -1
  4. data/stash_magic.rb +3 -3
  5. 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
- require 'stash_magic'
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
- class Treasure < ::Sequel::Model
26
- include ::StashMagic
27
- self.public_root = ::File.expand_path(::File.dirname(__FILE__)+'/public')
28
- end
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
- class Treasure < ::Sequel::Model
33
- ::StashMagic.with_public_root ::File.expand_path(::File.dirname(__FILE__)+'/public')
34
- end
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
- class Treasure < ::Sequel::Model
39
- ::StashMagic.with_public_root ::File.expand_path(::File.dirname(__FILE__)+'/public')
40
-
41
- stash :map
42
- stash :stamp
43
- end
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
- class Treasure < ::Sequel::Model
48
- ::StashMagic.with_public_root ::File.expand_path(::File.dirname(__FILE__)+'/public')
49
-
50
- stash :map
51
- stash :stamp, :accept_gif => false, :limit => 512000
52
- end
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
- :map => {},
58
- :stamp => {:accept_gif => false, :limit => 512000}
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
- @treasure_instance.map # { :name => 'map.pdf', :type => 'application/pdf', :size => 1024 }
64
- @treasure_instance.stamp # nil if there is no stamp yet
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
- @treasure_instance.map = nil # Will delete this attachment as expected
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
- @treasure_instance.file_url(:map) # The original file
76
- @treasure_instance.file_url(:map, 'thumb.gif') # The picture in a thumb.gif style (see next chapter to learn about styles)
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
- @treasure_instance.file_url(:map, nil, true) # /absolute/path/to/public/stash/Treasure/1/map.pdf
81
- @treasure_instance.file_url(:map, 'thumb.gif', true) # /absolute/path/to/public/stash/Treasure/1/map.thumb.gif
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
- mini.gif
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
- @treasure_instance.convert :portrait, '-resize 100x75', 'mini.gif'
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
- @treasure_instance.image_magick :portrait, 'mini.gif' do
135
+ @treasure_instance.image_magick :portrait, 'mini.gif' do
120
136
  im_resize(100, 75)
121
- end
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
- im_write("-negate")
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
- @treasure_instance.image_magick :portrait, 'mini.gif' do
168
- im_negate
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
- end
172
-
187
+ end
188
+
173
189
  Which will secretly do something like:
174
190
 
175
- convert /path/to/portrait.jpg -negate -crop 200x100+20+10 +repage -resize '200x100^' -gravity North -extent 200x100 /path/to/portrait.mini.gif
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
- after_stash(attachment_name)
184
- image_magick(attachment_name, 'square.jpg') { im_resize(200, 200, '^') }
185
- end
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
- after_stash(attachment_name)
190
- attachment_hash = self.send(attachment_name)
191
- image_magick(attachment_name, 'square.jpg') { im_resize(200, 200, '^') } if attachment_hash[:type][/^image\//]
192
- end
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.2"
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
- # GETTER
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
- # SETTER
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: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
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-10-18 00:00:00 +01:00
18
+ date: 2010-12-08 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies: []
21
21