ruby-thumbor 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = ruby-thumbor {<img src="https://secure.travis-ci.org/heynemann/ruby-thumbor.png?branch=master" alt="Build Status" />}[http://travis-ci.org/heynemann/ruby-thumbor]
1
+ = ruby-thumbor {<img src="https://secure.travis-ci.org/heynemann/ruby-thumbor.png?branch=master" alt="Build Status" />}[http://travis-ci.org/heynemann/ruby-thumbor] {<img src="https://gemnasium.com/heynemann/ruby-thumbor.png" alt="Dependency Status" />}[https://gemnasium.com/heynemann/ruby-thumbor]
2
2
 
3
3
  * http://github.com/heynemann/ruby-thumbor
4
4
 
@@ -17,15 +17,32 @@ No dependencies required for regular usage.
17
17
 
18
18
  * thumbor (http://github.com/globocom/thumbor) for running ruby-thumbor tests.
19
19
 
20
+ == INSTALL:
21
+
22
+ gem install ruby-thumbor
23
+
24
+ gem 'ruby-thumbor'
25
+
26
+
20
27
  == USAGE:
21
28
 
22
- crypto = CryptoURL.new :key => 'my-security-key'
29
+ require 'ruby-thumbor'
30
+
31
+ crypto = Thumbor::CryptoURL.new :key => 'my-security-key'
23
32
 
24
33
  url = crypto.generate :width => 200, :height => 300, :image => 'my.server.com/path/to/image.jpg'
25
34
 
26
35
  # url will contain something like:
27
36
  # /2913921in321n3k2nj32hjhj3h22/my.server.com/path/to/image.jpg
28
37
 
38
+ or
39
+
40
+ require 'ruby-thumbor'
41
+
42
+ Thumbor.key = 'my-security-key'
43
+ image = Thumbor::Cascade.new('my.server.com/path/to/image.jpg')
44
+ image.width(300).height(200).watermark_filter('http://my-server.com/image.png', 30).generate
45
+
29
46
  Available arguments to the generate method:
30
47
 
31
48
  :meta => bool - flag that indicates that thumbor should return only meta-data on the operations it would
@@ -51,10 +68,6 @@ Available arguments to the generate method:
51
68
 
52
69
  If you need more info on what each option does, check thumbor's documentation at https://github.com/globocom/thumbor/wiki.
53
70
 
54
- == INSTALL:
55
-
56
- * sudo gem install ruby-thumbor
57
-
58
71
  == CONTRIBUTIONS:
59
72
 
60
73
  * Hugo Lopes (hugobr) - Fixes in the usage readme part of the docs.
data/lib/ruby-thumbor.rb CHANGED
@@ -1,146 +1,13 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
- require 'openssl'
5
- require 'base64'
6
- require 'digest/md5'
7
- require 'cgi'
1
+ require 'thumbor/crypto_url'
2
+ require 'thumbor/cascade'
8
3
 
9
4
  module Thumbor
10
- VERSION = '1.0.0'
11
-
12
- class CryptoURL
13
- attr_accessor :key, :computed_key
14
-
15
- def initialize(key)
16
- @key = key
17
- @computed_key = (key * 16)[0..15]
18
- end
19
-
20
- def pad(s)
21
- s + ("{" * (16 - s.length % 16))
22
- end
23
-
24
- def calculate_width_and_height(url_parts, options)
25
- width = options[:width]
26
- height = options[:height]
27
-
28
- if width and options[:flip]
29
- width = width * -1
30
- end
31
- if height and options[:flop]
32
- height = height * -1
33
- end
34
-
35
- if width or height
36
- width = 0 if not width
37
- height = 0 if not height
38
- end
39
-
40
- has_width = width
41
- has_height = height
42
- if options[:flip] and not has_width and not has_height
43
- width = "-0"
44
- height = '0' if not has_height and not options[:flop]
45
- end
46
- if options[:flop] and not has_width and not has_height
47
- height = "-0"
48
- width = '0' if not has_width and not options[:flip]
49
- end
50
-
51
- if width or height
52
- width = width.to_s
53
- height = height.to_s
54
- url_parts.push(width << 'x' << height)
55
- end
56
- end
57
-
58
- def url_for(options, include_hash = true)
59
- if not options[:image]
60
- raise 'image is a required argument.'
61
- end
62
-
63
- url_parts = Array.new
64
-
65
- if options[:meta]
66
- url_parts.push('meta')
67
- end
68
-
69
- crop = options[:crop]
70
- if crop
71
- crop_left = crop[0]
72
- crop_top = crop[1]
73
- crop_right = crop[2]
74
- crop_bottom = crop[3]
75
-
76
- if crop_left > 0 or crop_top > 0 or crop_bottom > 0 or crop_right > 0
77
- url_parts.push(crop_left.to_s << 'x' << crop_top.to_s << ':' << crop_right.to_s << 'x' << crop_bottom.to_s)
78
- end
79
- end
80
-
81
- if options[:fit_in]
82
- url_parts.push('fit-in')
83
- end
84
-
85
- calculate_width_and_height(url_parts, options)
86
-
87
- if options[:halign] and options[:halign] != :center
88
- url_parts.push(options[:halign])
89
- end
90
-
91
- if options[:valign] and options[:valign] != :middle
92
- url_parts.push(options[:valign])
93
- end
94
-
95
- if options[:smart]
96
- url_parts.push('smart')
97
- end
98
-
99
- if options[:filters] && !options[:filters].empty?
100
- filter_parts = []
101
- options[:filters].each do |filter|
102
- filter_parts.push(filter)
103
- end
104
-
105
- url_parts.push("filters:#{ filter_parts.join(':') }")
106
- end
107
-
108
- if include_hash
109
- image_hash = Digest::MD5.hexdigest(options[:image])
110
- url_parts.push(image_hash)
111
- end
112
-
113
- return url_parts.join('/')
114
- end
115
-
116
- def url_safe_base64(str)
117
- Base64.encode64(str).gsub('+', '-').gsub('/', '_').gsub!(/[\n]/, '')
118
- end
119
-
120
- def generate_old(options)
121
- url = pad(url_for(options))
122
- cipher = OpenSSL::Cipher::Cipher.new('aes-128-ecb').encrypt
123
- cipher.key = @computed_key
124
- encrypted = cipher.update(url)
125
- based = url_safe_base64(encrypted)
126
-
127
- "/#{based}/#{options[:image]}"
128
- end
129
-
130
- def generate_new(options)
131
- url_options = url_for(options, false)
132
- url = "#{url_options}/#{options[:image]}"
133
-
134
- signature = OpenSSL::HMAC.digest('sha1', @key, url)
135
- signature = url_safe_base64(signature)
136
-
137
- "/#{signature}/#{url}"
138
- end
139
-
140
- def generate(options)
141
- return generate_old(options) if options[:old]
142
- generate_new(options)
143
- end
144
- end
5
+ def self.key=(key)
6
+ @@key = key
7
+ end
145
8
 
9
+ def self.key
10
+ @@key
11
+ end
146
12
  end
13
+
@@ -0,0 +1,70 @@
1
+ require 'forwardable'
2
+ require 'openssl'
3
+ require 'base64'
4
+ require 'digest/md5'
5
+ require 'cgi'
6
+
7
+ module Thumbor
8
+ class Cascade
9
+ attr_accessor :image, :old_crypto, :options, :filters
10
+
11
+ @available_options = [:meta, :crop, :width, :height, :flip,:flop, :halign, :valign, :smart, :fit_in, :old, :trim]
12
+
13
+ extend Forwardable
14
+
15
+ def_delegators :@old_crypto, :computed_key
16
+
17
+ @available_options.each do |opt|
18
+ define_method(opt) do |*args|
19
+ args = [true] if args.empty?
20
+ @options[opt] = args
21
+ self
22
+ end
23
+ end
24
+
25
+ def initialize(image=nil)
26
+ @image = image
27
+ @options = {}
28
+ @filters = []
29
+ @old_crypto = Thumbor::CryptoURL.new Thumbor.key
30
+ end
31
+
32
+ def url_for
33
+ @old_crypto.url_for prepare_options(@options).merge({:image => @image, :filters => @filters})
34
+ end
35
+
36
+ def generate
37
+ @old_crypto.generate prepare_options(@options).merge({:image => @image, :filters => @filters})
38
+ end
39
+
40
+ def method_missing(m, *args)
41
+ if /^(.+)_filter$/.match(m.to_s)
42
+ @filters << "#{$1}(#{escape_args(args).join(',')})"
43
+ self
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def escape_args(args)
52
+ args.map do |arg|
53
+ arg = CGI::escape(arg) if arg.is_a? String and arg.match(/^https?:\/\//)
54
+ arg
55
+ end
56
+ end
57
+
58
+ def prepare_options(options)
59
+ options.reduce({}) do |final_options, item|
60
+ value = if item[1].length == 1
61
+ item[1].first
62
+ else
63
+ item[1]
64
+ end
65
+ final_options[item[0]] = value
66
+ final_options
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,146 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ require 'digest/md5'
4
+ require 'cgi'
5
+
6
+ module Thumbor
7
+ class CryptoURL
8
+ attr_accessor :computed_key
9
+
10
+ def initialize(key)
11
+ Thumbor.key = key
12
+ @computed_key = (Thumbor.key * 16)[0..15]
13
+ end
14
+
15
+ def pad(s)
16
+ s + ("{" * (16 - s.length % 16))
17
+ end
18
+
19
+ def calculate_width_and_height(url_parts, options)
20
+ width = options[:width]
21
+ height = options[:height]
22
+
23
+ if width and options[:flip]
24
+ width = width * -1
25
+ end
26
+ if height and options[:flop]
27
+ height = height * -1
28
+ end
29
+
30
+ if width or height
31
+ width = 0 if not width
32
+ height = 0 if not height
33
+ end
34
+
35
+ has_width = width
36
+ has_height = height
37
+ if options[:flip] and not has_width and not has_height
38
+ width = "-0"
39
+ height = '0' if not has_height and not options[:flop]
40
+ end
41
+ if options[:flop] and not has_width and not has_height
42
+ height = "-0"
43
+ width = '0' if not has_width and not options[:flip]
44
+ end
45
+
46
+ if width or height
47
+ width = width.to_s
48
+ height = height.to_s
49
+ url_parts.push(width << 'x' << height)
50
+ end
51
+ end
52
+
53
+ def url_for(options, include_hash = true)
54
+ if not options[:image]
55
+ raise 'image is a required argument.'
56
+ end
57
+
58
+ url_parts = Array.new
59
+
60
+ if options[:meta]
61
+ url_parts.push('meta')
62
+ end
63
+
64
+ crop = options[:crop]
65
+ if crop
66
+ crop_left = crop[0]
67
+ crop_top = crop[1]
68
+ crop_right = crop[2]
69
+ crop_bottom = crop[3]
70
+
71
+ if crop_left > 0 or crop_top > 0 or crop_bottom > 0 or crop_right > 0
72
+ url_parts.push(crop_left.to_s << 'x' << crop_top.to_s << ':' << crop_right.to_s << 'x' << crop_bottom.to_s)
73
+ end
74
+ end
75
+
76
+ if options[:fit_in]
77
+ url_parts.push('fit-in')
78
+ end
79
+
80
+ calculate_width_and_height(url_parts, options)
81
+
82
+ if options[:halign] and options[:halign] != :center
83
+ url_parts.push(options[:halign])
84
+ end
85
+
86
+ if options[:valign] and options[:valign] != :middle
87
+ url_parts.push(options[:valign])
88
+ end
89
+
90
+ if options[:smart]
91
+ url_parts.push('smart')
92
+ end
93
+
94
+ if options[:trim]
95
+ trim_options = ['trim']
96
+ trim_options << options[:trim] unless options[:trim] == true or options[:trim][0] == true
97
+ url_parts.push(trim_options.join(':'))
98
+ end
99
+
100
+ if options[:filters] && !options[:filters].empty?
101
+ filter_parts = []
102
+ options[:filters].each do |filter|
103
+ filter_parts.push(filter)
104
+ end
105
+
106
+ url_parts.push("filters:#{ filter_parts.join(':') }")
107
+ end
108
+
109
+ if include_hash
110
+ image_hash = Digest::MD5.hexdigest(options[:image])
111
+ url_parts.push(image_hash)
112
+ end
113
+
114
+ return url_parts.join('/')
115
+ end
116
+
117
+ def url_safe_base64(str)
118
+ Base64.encode64(str).gsub('+', '-').gsub('/', '_').gsub!(/[\n]/, '')
119
+ end
120
+
121
+ def generate_old(options)
122
+ url = pad(url_for(options))
123
+ cipher = OpenSSL::Cipher::Cipher.new('aes-128-ecb').encrypt
124
+ cipher.key = @computed_key
125
+ encrypted = cipher.update(url)
126
+ based = url_safe_base64(encrypted)
127
+
128
+ "/#{based}/#{options[:image]}"
129
+ end
130
+
131
+ def generate_new(options)
132
+ url_options = url_for(options, false)
133
+ url = "#{url_options}/#{options[:image]}"
134
+
135
+ signature = OpenSSL::HMAC.digest('sha1', Thumbor.key, url)
136
+ signature = url_safe_base64(signature)
137
+
138
+ "/#{signature}/#{url}"
139
+ end
140
+
141
+ def generate(options)
142
+ return generate_old(options) if options[:old]
143
+ generate_new(options)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,3 @@
1
+ module Thumbor
2
+ VERSION = '1.1.0'
3
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,15 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../lib')
2
- require 'ruby-thumbor'
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ if /^1\.9/ === RUBY_VERSION
5
+ require 'simplecov'
6
+
7
+ SimpleCov.start do
8
+ add_filter '/spec/'
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |c|
13
+ c.filter_run :focus => true
14
+ c.run_all_when_everything_filtered = true
15
+ end