short 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -9,13 +9,20 @@ for obvious reasons, the demo is configured with S3 disabled. However, if you ar
9
9
  to play around with `short` follow the instructions below and use `http://shortener1.heroku.com`
10
10
  as your the url you want to use.
11
11
 
12
+ ## Upgrading to 0.5.0
13
+
14
+ v0.5.0 updates how shortener stores some data. To assist in keeping your data,
15
+ v0.5.0 also provides a `rake short:data:dehyphenate_keys` task that will update
16
+ your existing data to the new schema. If have data from < 0.5 that you plan on
17
+ using in a >= 0.5 world, you should run this task.
18
+
12
19
  ### Installation
13
20
 
14
- is now as easy as
21
+ is now as easy as
15
22
 
16
23
  `gem install short`
17
24
 
18
- and
25
+ and
19
26
 
20
27
  `short`
21
28
 
@@ -84,7 +91,7 @@ the `Shortener` class or directly through the `Shortener::Short` class. You get:
84
91
  * fetch
85
92
  * delete
86
93
 
87
- methods, each of which will return a/n istance of the `Short` class which will
94
+ methods, each of which will return a/n istance of the `Short` class which will
88
95
  parse the data and provide some defaults and access to said data.
89
96
 
90
97
  ### Executable
data/bin/short CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
3
3
 
4
4
  require 'shortener'
5
5
 
@@ -89,11 +89,11 @@ shorts: #{index.length}
89
89
  EOD
90
90
  end
91
91
 
92
- def rake(arg)
93
- puts "running shortener rake task: #{arg}"
92
+ def build
94
93
  gem_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
95
- cmd = "cd #{gem_dir} && rake #{arg}"
96
- puts `#{cmd}`
94
+ require 'rake'; load 'shortener/tasks/heroku.rake'
95
+ Rake::Task[:'short:heroku:build'].execute
96
+ puts "Your shortener repo has been created, cd there to finish up the process"
97
97
  end
98
98
 
99
99
  def do_action(act, arg)
@@ -114,7 +114,7 @@ def usage
114
114
  delete: delete a short from the index.
115
115
  index: show summary data for all shorts.
116
116
 
117
- rake: run a shortener rake task. [heroku:build, heroku:setup...]
117
+ build: Generate a shortener server folder.
118
118
  server: start an instance of the shortener server locally.
119
119
 
120
120
  the default command is shorten, so that one could
@@ -167,8 +167,9 @@ when 'server'
167
167
  start_web
168
168
  when 'index'
169
169
  show_index
170
- when 'rake'
171
- do_action(:rake, ARGV[1])
170
+ when 'build'
171
+ #do_action(:build, ARGV[1])
172
+ build
172
173
  when 'delete'
173
174
  do_action(:delete, ARGV[1])
174
175
  when '-v', '--version'
@@ -1,5 +1,6 @@
1
1
  require 'uri'
2
2
  require 'yaml'
3
+ require 'redis-namespace'
3
4
 
4
5
  class Shortener
5
6
  # The class for storing Configuration Information
@@ -15,7 +16,7 @@ class Shortener
15
16
 
16
17
  OPTIONS = [:SHORTENER_URL, :DEFAULT_URL, :REDISTOGO_URL, :S3_KEY_PREFIX,
17
18
  :S3_ACCESS_KEY_ID, :S3_SECRET_ACCESS_KEY, :S3_DEFAULT_ACL, :S3_BUCKET,
18
- :DOTFILE_PATH, :S3_ENABLED]
19
+ :DOTFILE_PATH, :S3_ENABLED, :SHORTENER_NS]
19
20
 
20
21
  HEROKU_IGNORE = [:DOTFILE_PATH, :SHORTENER_URL, :REDISTOGO_URL]
21
22
 
@@ -32,6 +33,7 @@ class Shortener
32
33
  check_env
33
34
  @options = @options.merge!(opts)
34
35
  @options[:DEFAULT_URL] ||= '/index'
36
+ @options[:SHORTENER_NS] ||= :shortener
35
37
  else
36
38
  @options = Configuration.current.options
37
39
  end
@@ -61,6 +63,14 @@ class Shortener
61
63
  @options[opt]
62
64
  end
63
65
  end
66
+ alias ns shortener_ns
67
+
68
+ # a configured redis namespace instance
69
+ def redis
70
+ uri = self.redistogo_url
71
+ _r = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
72
+ Redis::Namespace.new(self.ns, redis: _r)
73
+ end
64
74
 
65
75
  # return the URI for the redistogo url
66
76
  def redistogo_url
@@ -82,7 +92,7 @@ class Shortener
82
92
  # are the necessary options present for S3 to work?
83
93
  def s3_configured
84
94
  ret = true
85
- [:S3_KEY_PREFIX, :S3_ACCESS_KEY_ID, :S3_SECRET_ACCESS_KEY,
95
+ [:S3_KEY_PREFIX, :S3_ACCESS_KEY_ID, :S3_SECRET_ACCESS_KEY,
86
96
  :S3_DEFAULT_ACL, :S3_BUCKET ].each do |k|
87
97
  ret = !@options[k].nil? unless ret == false
88
98
  end
@@ -14,8 +14,8 @@
14
14
  %td= short['shortened']
15
15
  %td
16
16
  %a{href: short['url']}= short['url'][0..50] + ((short['url'].length > 50) ? '...' : '')
17
- %td= short['set-count']
18
- %td= short['click-count'] || 0
17
+ %td= short['set_count']
18
+ %td= short['click_count'] || 0
19
19
  %td= ttl_display(short['expire'])
20
20
  %td= short['max-clicks'] || "&infin;"
21
21
  %td
@@ -92,7 +92,7 @@ class Shortener
92
92
  url = "https://s3.amazonaws.com/#{$conf.s3_bucket}/#{$conf.s3_key_prefix}/#{fname}"
93
93
  ext = File.extname(fname)[1..-1]
94
94
  data = {'url' => url, 's3' => true, 'shortened' => key,
95
- 'extension' => ext, 'set-count' => 1}
95
+ 'extension' => ext, 'set_count' => 1}
96
96
  data = params.merge(data)
97
97
 
98
98
  $redis.set(key, sha)
@@ -117,7 +117,7 @@ class Shortener
117
117
  unless options['expire'] || options['max-clicks']
118
118
  if (!prev_set['max-clicks'] && !prev_set['expire'] &&
119
119
  (prev_set['url'] == url.to_s))
120
- $redis.hincrby(check_key, 'set-count', 1)
120
+ $redis.hincrby(check_key, 'set_count', 1)
121
121
  return prev_set
122
122
  end
123
123
  end
@@ -138,7 +138,7 @@ class Shortener
138
138
  sha = Digest::SHA1.hexdigest(url.to_s)
139
139
  $redis.set(key, sha)
140
140
 
141
- hsh_data = {'shortened' => key, 'url' => url, 'set-count' => 1}
141
+ hsh_data = {'shortened' => key, 'url' => url, 'set_count' => 1}
142
142
  hsh_data['max-clicks'] = options['max-clicks'].to_i if options['max-clicks']
143
143
 
144
144
  if options['expire'] # set expire time if specified
@@ -159,7 +159,7 @@ class Shortener
159
159
  $redis.keys("data:#{sha}:*").each do |key|
160
160
  short = $redis.hgetall(key)
161
161
  unless short == {} || short['expire'] || short['max-clicks']
162
- $redis.hincrby(key, 'set-count', 1)
162
+ $redis.hincrby(key, 'set_count', 1)
163
163
  return short
164
164
  end
165
165
  end
@@ -277,14 +277,14 @@ class Shortener
277
277
  key = "data:#{sha}:#{id}"
278
278
  short = $redis.hgetall(key)
279
279
  not_expired = short.has_key?('expire') ? $redis.get(short['expire']) : true
280
- not_maxed = !(short['click-count'].to_i >= short['max-clicks'].to_i)
280
+ not_maxed = !(short['click_count'].to_i >= short['max-clicks'].to_i)
281
281
  short.has_key?('max-clicks') ? not_maxed : not_maxed = true
282
282
  if params[:captures].last == '.json'
283
283
  ret = short.merge({expired: not_expired.nil? , maxed: !not_maxed})
284
284
  content_type :json
285
285
  return ret.to_json
286
286
  else
287
- $redis.hincrby(key, 'click-count', 1) if not_expired && not_maxed
287
+ $redis.hincrby(key, 'click_count', 1) if not_expired && not_maxed
288
288
  if not_expired
289
289
  unless short['s3'] == 'true' && !(short['type'] == 'download')
290
290
  if not_maxed
@@ -0,0 +1,178 @@
1
+
2
+ namespace :short do
3
+
4
+ namespace :heroku do
5
+ $gem_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
6
+
7
+ def gem_file(f)
8
+ #ret = args.map {|f| File.join($gem_dir, f)}.join(" ")
9
+ File.join($gem_dir, f.to_s)
10
+ end
11
+
12
+ def _file(f)
13
+ fs = $existing_repo ? [f.to_s] : ['heroku', f.to_s]
14
+ File.join(Dir.pwd, *fs)
15
+ end
16
+
17
+ def _ep(f)
18
+ beginning_int = case f.split('/')[-3]
19
+ when 'shortener'
20
+ puts "************short" if ENV['VVERBOSE']
21
+ -2
22
+ when 'public', 'views', 's3'
23
+ puts "************public || s3" if ENV['VVERBOSE']
24
+ -4
25
+ when 'skin'
26
+ puts "************views" if ENV['VVERBOSE']
27
+ -5
28
+ else
29
+ puts "************else #{f.split('/')[-3]}" if ENV['VVERBOSE']
30
+ -3
31
+ end
32
+ end_point = f.split('/')[beginning_int..-1].join('/')
33
+ end
34
+
35
+ def _l(action, start, nd = nil)
36
+ if ENV['VERBOSE']
37
+ msg = "#{action}: #{start} "
38
+ msg += "=> #{nd}" unless nd.nil?
39
+ puts msg
40
+ end
41
+ end
42
+
43
+ def recursively_remove_files(dir)
44
+ dirs = Array.new
45
+ Dir[File.join(dir, '*')].each do |f|
46
+ next if f =~ /^(\.|\..*)/
47
+ if File.directory?(f)
48
+ if Dir.entries(f).empty?
49
+ _l(:removing_dir, f)
50
+ FileUtils.rmdir(f)
51
+ else
52
+ dirs << f
53
+ recursively_remove_files(f)
54
+ end
55
+ else
56
+ _l(:removing, f)
57
+ FileUtils.rm(f)
58
+ end
59
+ end
60
+ _l(:removing_dir, dirs)
61
+ FileUtils.rmdir(dirs)
62
+ end
63
+
64
+ desc "Build a Heroku Ready Git repo"
65
+ task :build do
66
+ FileUtils.mkdir(File.join(Dir.pwd, 'heroku')) unless $existing_repo
67
+ [:'server', :'server/public', :'server/views',
68
+ :'server/views/s3', :'server/public/flash',
69
+ :'server/public/skin', :'server/public/images',
70
+ :'server/public/skin/blue.monday'].each do |f|
71
+ unless File.exist?(_file(f))
72
+ puts "creating #{_file(f)}" if ENV['VERBOSE']
73
+ FileUtils.mkdir(_file(f))
74
+ end
75
+ end
76
+
77
+ ['server', 'server/public', 'server/views', :'server/views/s3',
78
+ :'server/public/flash', :'server/public/images', :'server/public/skin',
79
+ :'server/public/skin/blue.monday'].each do |end_point|
80
+ Dir["#{$gem_dir}/#{end_point}/**"].each do |f|
81
+ next if File.directory?(f)
82
+ end_point = _file(:"#{_ep(f)}")
83
+ _l(:copying, f, end_point)
84
+ FileUtils.cp(f, end_point)
85
+ end
86
+ end
87
+ _s, _e = gem_file('server.rb'), _file(:'main.rb')
88
+ _l(:copying, _s, _e)
89
+ FileUtils.cp(_s, _e)
90
+ _s, _e = gem_file('configuration.rb'), _file(:'configuration.rb')
91
+ _l(:copying, _s, _e)
92
+ FileUtils.cp(_s, _e)
93
+ _s, _e = _file('server/config.ru.template'), _file(:'config.ru')
94
+ _l(:renaming, _s, _e)
95
+ FileUtils.mv(_s, _e)
96
+ _s, _e = _file('server/Gemfile'), _file(:'Gemfile')
97
+ _l(:renaming, _s, _e)
98
+ FileUtils.mv(_s, _e)
99
+ _s, _e = _file(:'server/Gemfile.lock'), _file(:'Gemfile.lock')
100
+ _l(:renaming, _s, _e)
101
+ FileUtils.mv(_s, _e)
102
+ File.open(_file(:Rakefile), 'w+') do |f|
103
+ f.puts "load 'shortener/tasks/heroku.rake'"
104
+ end
105
+ end
106
+
107
+ desc "initialize the Git repo"
108
+ task :git do
109
+ cmd = "git init heroku && cd heroku && git add . && git commit -m initial"
110
+ sh cmd
111
+ end
112
+
113
+ desc "update with latest gem files"
114
+ task :update do
115
+ if `git status` =~ /.*working directory clean.*/
116
+ recursively_remove_files(Dir.pwd)
117
+ else
118
+ puts "working directory not clean, stash or commit your changes"
119
+ end
120
+ $existing_repo = true
121
+ Rake::Task[:'short:heroku:build'].execute
122
+ end
123
+
124
+ desc "config a Heroku app the way we need it. Optionally set APPNAME to set heroku app name"
125
+ task :config do
126
+ require 'shortener'
127
+ $name = ENV['APPNAME'] || "shner-#{`whoami`.chomp}"
128
+ cmd = Dir.pwd =~ /heroku$/ ? "" : "cd heroku && "
129
+ cmd += "heroku create #{$name}"
130
+ cmd += " && heroku addons:add redistogo:nano"
131
+ cmd += " && heroku config:add #{Shortener::Configuration.new.to_params}"
132
+ cmd += " && heroku addons:add custom_domains:basic"
133
+ sh cmd
134
+ end
135
+
136
+ desc "Push to Heroku"
137
+ task :push do
138
+ cmd = Dir.pwd =~ /heroku$/ ? "" : "cd heroku && "
139
+ cmd += "git push heroku master"
140
+ sh cmd
141
+ end
142
+
143
+ desc "Build, configure and push a shortener app to Heroku"
144
+ task :setup => [:build, :config, :push] do
145
+ puts "\nYour app has (hopefully) been created and pushed and available @" +
146
+ " http://#{$name}.heroku.com\n\n" +
147
+ "the Custom Domain Addon has been added, but still needs configuring, for" +
148
+ " steps see\n http://devcenter.heroku.com/articles/custom-domains"
149
+ end # => setup
150
+
151
+ end # => heroku
152
+
153
+ namespace :data do
154
+
155
+ desc "replace hyphenated keys with sanitized ones."
156
+ task :dehyphenate_keys do
157
+ require 'shortener'
158
+ redis = Shortener::Configuration.new.redis
159
+ redis.keys("data:*").each do |k|
160
+ hsh = redis.hgetall(k)
161
+ puts "checking #{hsh}" if ENV['VERBOSE']
162
+ set_count, click_count = hsh['set-count'], hsh['click_count']
163
+ arr = Array.new
164
+ arr.concat([:set_count, set_count]) unless set_count.nil?
165
+ arr.concat([:click_count, click_count]) unless click_count.nil?
166
+ puts "** setting: #{arr.inspect}" if ENV['VERBOSE']
167
+ unless arr.empty?
168
+ redis.hmset(k, *arr)
169
+ redis.hdel(k, 'set-count')
170
+ redis.hdel(k, 'click-count')
171
+ end
172
+ puts "#{k} afterwards: #{redis.hgetall(k)}" if ENV['VERBOSE']
173
+ end
174
+ end
175
+
176
+ end # => data
177
+
178
+ end # => short
@@ -1,6 +1,6 @@
1
1
 
2
2
  class Shortener
3
3
 
4
- VERSION = '0.4.3'
4
+ VERSION = '0.5.0'
5
5
 
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: short
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-20 00:00:00.000000000 Z
12
+ date: 2012-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
16
- requirement: &70312062943700 !ruby/object:Gem::Requirement
16
+ requirement: &70210385354960 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70312062943700
24
+ version_requirements: *70210385354960
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis-namespace
27
- requirement: &70312062941140 !ruby/object:Gem::Requirement
27
+ requirement: &70210385354320 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70312062941140
35
+ version_requirements: *70210385354320
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: haml
38
- requirement: &70312062940700 !ruby/object:Gem::Requirement
38
+ requirement: &70210385353860 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70312062940700
46
+ version_requirements: *70210385353860
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: turn
49
- requirement: &70312062940220 !ruby/object:Gem::Requirement
49
+ requirement: &70210385351560 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70312062940220
57
+ version_requirements: *70210385351560
58
58
  description: A (hopefully) easy and handy deployable APIable way to shorten links.
59
59
  email:
60
60
  - jake@jakewilkins.com
@@ -101,9 +101,9 @@ files:
101
101
  - lib/shortener/server/views/s3/video.haml
102
102
  - lib/shortener/server/views/upload.haml
103
103
  - lib/shortener/short.rb
104
+ - lib/shortener/tasks/heroku.rake
104
105
  - lib/shortener/version.rb
105
106
  - short.gemspec
106
- - tasks/heroku.rake
107
107
  - test/test_configuration.rb
108
108
  - test/test_server.rb
109
109
  - test/test_short.rb
data/tasks/heroku.rake DELETED
@@ -1,47 +0,0 @@
1
- $gem_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
2
- def gem_file(*args)
3
- ret = args.map {|f| File.join($gem_dir, f)}.join(" ")
4
- end
5
- namespace :heroku do
6
-
7
- desc "Build a Heroku Ready Git repo"
8
- task :build do
9
- cmd = ""#mkdir heroku"
10
- cmd += "mkdir heroku/server"
11
- cmd += " && cp -r #{gem_file("lib/shortener/server/*")} ./heroku/server/"
12
- cmd += " && cp #{gem_file('lib/shortener/server.rb')} ./heroku/main.rb"
13
- cmd += " && cp #{gem_file('lib/shortener/configuration.rb')} ./heroku/configuration.rb"
14
- cmd += " && mv ./heroku/server/config.ru.template ./heroku/config.ru"
15
- cmd += " && mv ./heroku/server/Gemfile ./heroku/server/Gemfile.lock ./heroku"
16
- cmd += " && git init heroku && cd heroku && git add . && git commit -m initial"
17
- sh cmd
18
- end
19
-
20
- desc "config a Heroku app the way we need it. Optionally set APPNAME to set heroku app name"
21
- task :config do
22
- require_relative '../lib/shortener'
23
- $name = ENV['APPNAME'] || "shner-#{`whoami`.chomp}"
24
- cmd = Dir.pwd =~ /heroku$/ ? "" : "cd heroku && "
25
- cmd += "heroku create #{$name}"
26
- cmd += " && heroku addons:add redistogo:nano"
27
- cmd += " && heroku config:add #{Shortener::Configuration.new.to_params}"
28
- cmd += " && heroku addons:add custom_domains:basic"
29
- sh cmd
30
- end
31
-
32
- desc "Push to Heroku"
33
- task :push do
34
- cmd = Dir.pwd =~ /heroku$/ ? "" : "cd heroku && "
35
- cmd += "git push heroku master"
36
- sh cmd
37
- end
38
-
39
- desc "Build, configure and push a shortener app to Heroku"
40
- task :setup => [:build, :config, :push] do
41
- puts "\nYour app has (hopefully) been created and pushed and available @" +
42
- " http://#{$name}.heroku.com\n\n" +
43
- "the Custom Domain Addon has been added, but still needs configuring, for" +
44
- " steps see\n http://devcenter.heroku.com/articles/custom-domains"
45
- end
46
-
47
- end