bitly4r 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8526b72584f4eeb4175cf447451f8aeb5db38d3d4285a98b710dc7d113147762
4
+ data.tar.gz: ab0137814f7761acf5c19c4eff4653d84e81a2f3276be962cd0edba94d44489d
5
+ SHA512:
6
+ metadata.gz: 6c170ec3149dc568e58b0efec03e55566d3fa53a6df8620eb241f0c583735daf8c777b15b3128a11b95887fd69f58e2dae40b2e67d3c0584cb0e7828bfa0c616
7
+ data.tar.gz: 87f9651ee1d6154015f2420950c6934f0bdb42c3b5208fcab516310d24f2e8b6894c2f88deaadc216bceabef3a83a2834b8920e13bfceb4cf52d9b6c5508915f
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ = 0.2.0
2
+
3
+ * upgrade to bit.ly API version 4.0.0
4
+ * upgrade to Ruby 3
5
+ * remove login + password + api_key, replace with Authentication Token (token)
6
+ * the 'stats' and 'errors' methods are obsolete
7
+ * a `TOKEN` environment variable must be passed to the Test Suite
8
+
9
+ = 0.1.1
10
+
11
+ * the build never included 'bitly4r.gemspec'
12
+
1
13
  = 0.1.0
2
14
 
3
15
  * Initial gem release of 0.1 coebase.
data/README.rdoc CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  A Ruby API for the http://bit.ly URL-shortening service
4
4
 
5
+
5
6
  == SimpleClient
6
7
 
7
8
  This example uses a simpler construction and invocation technique.
@@ -10,17 +11,19 @@ For when you just need the URLs, and not any additional data.
10
11
  require 'rubygems'
11
12
  require 'bitly4r'
12
13
 
13
- login, api_key = 'bitlyapidemo', 'R_0da49e0a9118ff35f52f629d2d71bf07'
14
+ access_token = ENV['TOKEN']
14
15
  long_url = 'http://rubyforge.org/'
15
16
 
16
- client = Bitly4R.Keyed(login, api_key)
17
+ client = Bitly4R.Token(access_token)
17
18
 
18
19
  # shorten
19
20
  short_url = client.shorten(long_url)
21
+ puts "short_url = #{short_url}"
20
22
 
21
23
  # re-expand
22
24
  raise 'what the?' unless (long_url == client.expand(short_url))
23
25
 
26
+
24
27
  == Client
25
28
 
26
29
  This example uses a full-fledged construction and invocation technique.
@@ -29,36 +32,39 @@ The URLs are returned by the <tt>to_s</tt> methods of the Response objects, and
29
32
  require 'rubygems'
30
33
  require 'bitly4r'
31
34
 
32
- login, api_key = 'bitlyapidemo', 'R_0da49e0a9118ff35f52f629d2d71bf07'
35
+ access_token = ENV['TOKEN']
33
36
  long_url = 'http://rubyforge.org/'
34
37
 
35
- client = Bitly4R::Client.new(:login => login, :api_key => api_key)
38
+ client = Bitly4R::Client.new(:token => access_token)
36
39
 
37
40
  # shorten
38
41
  short_url = client.shorten(long_url).to_s
42
+ puts "short_url = #{short_url}"
39
43
 
40
44
  # re-expand
41
45
  raise 'aww, cmon!' unless (long_url == client.expand(short_url).to_s)
42
46
 
47
+
43
48
  == Support
44
49
 
50
+ This Client uses version 4.0.0 of the API (eg. '/v4/*').
51
+ It supports Access Token credentials.
52
+
45
53
  This gem supports the following API commands:
46
54
 
47
- * shorten
48
- * expand
49
- * info
50
- * stats
51
- * errors
55
+ * `POST /v4/shorten`
56
+ * `POST /v4/expand`
57
+ * `GET /v4/bitlinks/:bitlink`
52
58
 
53
59
  For more information, see the API documentation:
54
60
 
55
- * http://code.google.com/p/bitly-api/wiki/ApiDocumentation
61
+ * http://cantremember.github.io/bitly4r/
56
62
 
57
63
  == Contributing
58
64
 
59
65
  === Issue Tracking and Feature Requests
60
66
 
61
- * http://bitly4r.rubyforge.org
67
+ * https://github.com/cantremember/bitly4r
62
68
 
63
69
  == Community
64
70
 
data/Rakefile CHANGED
@@ -6,33 +6,30 @@ task :default => :test
6
6
 
7
7
  # SPECS ===============================================================
8
8
 
9
- desc 'Run specs with story style output'
10
- task :spec do
11
- sh 'specrb --specdox -Ilib:test test/*_test.rb'
12
- end
13
-
14
9
  desc 'Run specs with unit test style output'
15
10
  task :test => FileList['test/*_test.rb'] do |t|
16
- suite = t.prerequisites.map{|f| "-r#{f.chomp('.rb')}"}.join(' ')
17
- sh "ruby -Ilib:test #{suite} -e ''", :verbose => false
11
+ suite = t.prerequisites.join(' ')
12
+ sh "ruby -Ilib:test #{suite}", :verbose => false
18
13
  end
19
14
 
20
15
  # PACKAGING ============================================================
21
16
 
22
17
  # Load the gemspec using the same limitations as github
23
18
  def spec
24
- @spec ||=
25
- begin
26
- require 'rubygems/specification'
27
- data = File.read('sinatra.gemspec')
28
- spec = nil
29
- Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
30
- spec
31
- end
19
+ @spec ||=
20
+ begin
21
+ require 'rubygems/specification'
22
+ data = File.read('bitly4r.gemspec')
23
+ spec = nil
24
+ # OS X didn't like SAFE = 2
25
+ # (eval):25:in `glob': Insecure operation - glob
26
+ Thread.new { spec = eval("$SAFE = 2\n#{data}") }.join
27
+ spec
28
+ end
32
29
  end
33
30
 
34
31
  def package(ext='')
35
- "dist/sinatra-#{spec.version}" + ext
32
+ "dist/bitly4r-#{spec.version}" + ext
36
33
  end
37
34
 
38
35
  desc 'Build packages'
@@ -40,123 +37,85 @@ task :package => %w[.gem .tar.gz].map {|e| package(e)}
40
37
 
41
38
  desc 'Build and install as local gem'
42
39
  task :install => package('.gem') do
43
- sh "gem install #{package('.gem')}"
40
+ sh "gem install #{package('.gem')}"
44
41
  end
45
42
 
46
43
  directory 'dist/'
47
44
 
48
- file package('.gem') => %w[dist/ sinatra.gemspec] + spec.files do |f|
49
- sh "gem build sinatra.gemspec"
50
- mv File.basename(f.name), f.name
45
+ file package('.gem') => %w[dist/ bitly4r.gemspec] + spec.files do |f|
46
+ sh "gem build bitly4r.gemspec"
47
+ mv File.basename(f.name), f.name
51
48
  end
52
49
 
53
50
  file package('.tar.gz') => %w[dist/] + spec.files do |f|
54
- sh "git archive --format=tar HEAD | gzip > #{f.name}"
51
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
55
52
  end
56
53
 
57
- # Rubyforge Release / Publish Tasks ==================================
54
+ # Release / Publish Tasks ==================================
58
55
 
59
56
  desc 'Publish website to rubyforge'
60
- task 'publish:doc' => 'doc/api/index.html' do
61
- sh 'scp -rp doc/* rubyforge.org:/var/www/gforge-projects/sinatra/'
62
- end
63
57
 
64
- task 'publish:gem' => [package('.gem'), package('.tar.gz')] do |t|
65
- sh <<-end
66
- rubyforge add_release sinatra sinatra #{spec.version} #{package('.gem')} &&
67
- rubyforge add_file sinatra sinatra #{spec.version} #{package('.tar.gz')}
68
- end
58
+ # https://guides.rubygems.org/publishing/#publishing-to-rubygemsorg
59
+ task 'publish:gem' => [package('.gem')] do |t|
60
+ sh <<-end
61
+ gem push #{package('.gem')}
62
+ end
69
63
  end
70
64
 
71
65
  # Website ============================================================
72
- # Building docs requires HAML and the hanna gem:
73
- # gem install mislav-hanna --source=http://gems.github.com
66
+ # Building docs
74
67
 
75
- task 'doc' => ['doc:api','doc:site']
68
+ =begin
69
+ NOTE: i honestly don't know how `rake doc` is working
70
+ but it does!
76
71
 
77
- desc 'Generate Hanna RDoc under doc/api'
78
- task 'doc:api' => ['doc/api/index.html']
72
+ Manual process for publish to Github Pages
73
+ http://cantremember.github.io/bitly4r/
79
74
 
80
- file 'doc/api/index.html' => FileList['lib/**/*.rb','README.rdoc'] do |f|
81
- rb_files = f.prerequisites
82
- sh((<<-end).gsub(/\s+/, ' '))
83
- hanna --charset utf8 \
84
- --fmt html \
85
- --inline-source \
86
- --line-numbers \
87
- --main README.rdoc \
88
- --op doc/api \
89
- --title 'Sinatra API Documentation' \
90
- #{rb_files.join(' ')}
91
- end
92
- end
93
- CLEAN.include 'doc/api'
75
+ ```bash
76
+ # no outstanding Git changes, then ...
77
+ rake doc
94
78
 
95
- def rdoc_to_html(file_name)
96
- require 'rdoc/markup/to_html'
97
- rdoc = RDoc::Markup::ToHtml.new
98
- rdoc.convert(File.read(file_name))
99
- end
79
+ git checkout gh-pages
80
+ cp -r doc/* .
81
+ git add .
100
82
 
101
- def haml(locals={})
102
- require 'haml'
103
- template = File.read('doc/template.haml')
104
- haml = Haml::Engine.new(template, :format => :html4, :attr_wrapper => '"')
105
- haml.render(Object.new, locals)
106
- end
83
+ # commit & push
84
+ ```
85
+ =end
107
86
 
108
- desc 'Build website HTML and stuff'
109
- task 'doc:site' => ['doc/index.html', 'doc/book.html']
87
+ task 'doc' => ['doc:api']
110
88
 
111
- file 'doc/index.html' => %w[README.rdoc doc/template.haml] do |file|
112
- File.open(file.name, 'w') do |file|
113
- file << haml(:title => 'Sinatra', :content => rdoc_to_html('README.rdoc'))
114
- end
115
- end
116
- CLEAN.include 'doc/index.html'
89
+ desc 'Generate RDoc under doc/api'
90
+ task 'doc:api' => ['doc/api/index.html']
117
91
 
118
- file 'doc/book.html' => ['book/output/sinatra-book.html'] do |file|
119
- File.open(file.name, 'w') do |file|
120
- book_content = File.read('book/output/sinatra-book.html')
121
- file << haml(:title => 'Sinatra Book', :content => book_content)
122
- end
92
+ file 'doc/api/index.html' => FileList['lib/**/*.rb','README.rdoc','CHANGELOG','LICENSE'] do |f|
93
+ rb_files = f.prerequisites
94
+ sh((<<-end).gsub(/\s+/, ' '))
95
+ rdoc --line-numbers --inline-source --title Bitly4R --main README.rdoc
96
+ #{rb_files.join(' ')}
97
+ end
123
98
  end
124
- CLEAN.include 'doc/book.html'
125
-
126
- file 'book/output/sinatra-book.html' => FileList['book/**'] do |f|
127
- unless File.directory?('book')
128
- sh 'git clone git://github.com/cschneid/sinatra-book.git book'
129
- end
130
- sh((<<-SH).strip.gsub(/\s+/, ' '))
131
- cd book &&
132
- git fetch origin &&
133
- git rebase origin/master &&
134
- thor book:build
135
- SH
136
- end
137
- CLEAN.include 'book/output/sinatra-book.html'
138
-
139
- desc 'Build the Sinatra book'
140
- task 'doc:book' => ['book/output/sinatra-book.html']
99
+ CLEAN.include 'doc/api'
141
100
 
142
101
  # Gemspec Helpers ====================================================
143
102
 
144
- file 'sinatra.gemspec' => FileList['{lib,test,images}/**','Rakefile'] do |f|
145
- # read spec file and split out manifest section
146
- spec = File.read(f.name)
147
- parts = spec.split(" # = MANIFEST =\n")
148
- fail 'bad spec' if parts.length != 3
149
- # determine file list from git ls-files
150
- files = `git ls-files`.
151
- split("\n").
152
- sort.
153
- reject{ |file| file =~ /^\./ }.
154
- reject { |file| file =~ /^doc/ }.
155
- map{ |file| " #{file}" }.
156
- join("\n")
157
- # piece file back together and write...
158
- parts[1] = " s.files = %w[\n#{files}\n ]\n"
159
- spec = parts.join(" # = MANIFEST =\n")
160
- File.open(f.name, 'w') { |io| io.write(spec) }
161
- puts "updated #{f.name}"
103
+ file 'bitly4r.gemspec' => FileList['{lib,test}/**','Rakefile'] do |f|
104
+ # read spec file and split out manifest section
105
+ spec = File.read(f.name)
106
+ parts = spec.split("# = MANIFEST =\n")
107
+ fail 'bad spec' if parts.length != 3
108
+ # determine file list from git ls-files
109
+ files = `git ls-files`.
110
+ split("\n").
111
+ sort.
112
+ reject{ |file| file =~ /^\./ }.
113
+ reject { |file| file =~ /^doc/ }.
114
+ map{ |file| " #{file}" }.
115
+ join("\n")
116
+ # piece file back together and write...
117
+ parts[1] = " s.files = %w[\n#{files}\n ]\n"
118
+ spec = parts.join("# = MANIFEST =\n")
119
+ File.open(f.name, 'w') { |io| io.write(spec) }
120
+ puts "updated #{f.name}"
162
121
  end
data/bitly4r.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ Gem::Specification.new do |s|
2
+ s.required_ruby_version = '>= 3.0'
3
+
4
+ s.name = 'bitly4r'
5
+ s.version = '0.2.0'
6
+ # s.date = "2023-04-30"
7
+
8
+ s.description = "Bitly4R : A Ruby API for the http://bit.ly URL-shortening service"
9
+ s.summary = "#{s.name} #{s.version}"
10
+
11
+ s.homepage = "http://wiki.cantremember.com/Bitly4R"
12
+ s.authors = ["Dan Foley"]
13
+ s.email = 'admin@cantremember.com'
14
+ s.license = 'WTFPL'
15
+
16
+ # = MANIFEST =
17
+ s.files = %w[
18
+ CHANGELOG
19
+ LICENSE
20
+ README.rdoc
21
+ Rakefile
22
+ bitly4r.gemspec
23
+ container
24
+ lib/bitly4r.rb
25
+ lib/bitly4r/client.rb
26
+ lib/bitly4r/definitions.rb
27
+ lib/bitly4r/objects.rb
28
+ test/client_test.rb
29
+ test/definitions_test.rb
30
+ test/objects_test.rb
31
+ test/test_helper.rb
32
+ ]
33
+ # = MANIFEST =
34
+
35
+ s.files += Dir.glob('lib/**/*.rb')
36
+ # s.test_files = Dir.glob('test/**/*.rb')
37
+
38
+ s.require_paths = %w{lib}
39
+
40
+ # only because there ain't no spaces in the title ...
41
+ s.rdoc_options = %w{ --line-numbers --inline-source --title Bitly4R --main README.rdoc }
42
+ s.extra_rdoc_files = %w{ README.rdoc CHANGELOG LICENSE }
43
+ end
data/container ADDED
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ docker run --name bitly4r --rm --privileged \
3
+ --mount type=bind,target=/opt/project,source="$(pwd)" \
4
+ --workdir /opt/project \
5
+ -it ruby:3.1 bash
@@ -9,31 +9,20 @@ module Bitly4R
9
9
  #
10
10
  #A client object for accessing the bit.ly API.
11
11
  #
12
- #* Supports both API key and HTTP Auth credentials (although HTTP Auth / password-based doesn't seem to work)
13
- #* Works with version 2.0.1 of the API
14
- #* Uses XML for marshalling, for cheap & easy text parsing.
12
+ #* This Client uses version 4.0.0 of the API (eg. '/v4/*').
13
+ #* It supports Access Token credentials.
15
14
  #
16
15
  #See the API documentation:
17
- #* http://code.google.com/p/bitly-api/wiki/ApiDocumentation
18
- #* http://bit.ly
16
+ #* https://dev.bitly.com/docs/
19
17
  class Client
20
- #:nodoc:
21
- BASE_PARAMS = Params.new
22
- BASE_PARAMS[:version] = '2.0.1'
23
- BASE_PARAMS[:format] = 'xml'
24
-
25
- #The login credential provided at construction.
26
- attr_reader :login
27
- #The password credential provided at construction.
28
- attr_reader :password
29
- #The API key credential provided at construction.
30
- attr_reader :api_key
18
+ #The Access Token credential provided at construction.
19
+ attr_reader :token
31
20
 
32
21
  #Constructs a new client.
33
22
  #
34
23
  #Any tuples provided in the optional Hash are injected into instance variables.
35
24
  #
36
- #You must provide a login, and either an API key (<tt>api_key</tt>) or a password.
25
+ #You must provide an Access Token (<tt>token</tt>).
37
26
  def initialize(ops={})
38
27
  # for the readers
39
28
  # not necessary, but polite
@@ -41,105 +30,77 @@ module Bitly4R
41
30
  instance_variable_set "@#{k}".to_sym, v
42
31
  end
43
32
 
44
- raise Error.new("you must provide a login") unless self.login
45
- raise Error.new("you must provide either an API key or a password") unless (self.api_key or self.password)
46
-
47
- # now, a client-izec set of parameters
48
- @client_params = BASE_PARAMS.clone.merge(ops)
33
+ raise Error.new("you must provide an Access Token") unless self.token
49
34
  end
50
35
 
51
36
 
52
37
  #Invokes the API's <b>shorten</b> method.
53
38
  #That's pretty much what makes bit.ly a valuable service.
39
+ #
40
+ #https://dev.bitly.com/api-reference/#createBitlink
54
41
  #
55
42
  #A Response is returned.
56
- #Response.to_s will return the <tt>shortUrl</tt> / <tt>short_url</tt> value.
57
- #
58
- #You can take the shortened URL and re- expand it.
59
- def shorten(long_url)
43
+ #Response.to_s will return the <tt>link</tt> value.
44
+ #
45
+ #You can take the shortened URL and re-expand it.
46
+ #
47
+ #<i>ops</i> allows for additional API parameters
48
+ #<ul>
49
+ # <li><tt>group_guid</tt></li>
50
+ # <li><tt>domain</tt></li>
51
+ #</ul>
52
+ def shorten(long_url, ops={})
60
53
  return nil unless long_url
61
- assert_codes(execute(:shorten, :short_url) do |params|
62
- params[:longUrl] = long_url
63
- end)
54
+ return execute_post('shorten', :link) do |params|
55
+ params[:long_url] = long_url
56
+ params.merge!(ops)
57
+ end
64
58
  end
65
59
 
66
60
  #Invokes the API's <b>expand</b> method.
67
61
  #It reverses a shorten; the original full URL is re-hydrated.
62
+ #
63
+ #https://dev.bitly.com/api-reference/#expandBitlink
68
64
  #
69
- #For <i>param</i>, you can provide a previously-shortened URL from the bit.ly service.
70
- #If so, you do not need to provide <i>param_type</i> (though <tt>:short_url</tt> would be the proper symbol).
71
- #
72
- #Alternately, you can provide a hash code returned by the bit.ly service.
73
- #In this case, provide <tt>:hash</tt> as the <i>param_type</i>.
65
+ #For <i>url</i>, you can provide a previously-shortened URL from the bit.ly service.
66
+ #
67
+ #The URL must provide both a domain (hostname) and a Bitlink ID (path).
68
+ #A minimum-viable URL would be something along the lines of 'bit.ly/3ADCPDo'.
74
69
  #
75
70
  #A Response is returned.
76
- #Response.to_s will return the <tt>longUrl</tt> / <tt>long_url</tt> value.
77
- def expand(param, param_type=:short_url)
78
- return nil unless param && param_type
79
- assert_codes(execute(:expand, :long_url) do |params|
80
- params[Utility::camelize(param_type).to_sym] = param
81
- end)
71
+ #Response.to_s will return the <tt>long_url</tt> value.
72
+ def expand(url)
73
+ return nil unless url
74
+ uri = URI.parse(url)
75
+ bitlink = "#{uri.host}#{uri.path}"
76
+
77
+ return execute_post('expand', :long_url) do |params|
78
+ params[:bitlink_id] = bitlink
79
+ end
82
80
  end
83
81
 
84
82
  #Invokes the API's <b>info</b> method.
85
83
  #Information about the shortened URL is returned by the service.
84
+ #
85
+ #https://dev.bitly.com/api-reference/#getBitlink
86
86
  #
87
- #For <i>param</i>, you can provide a previously-shortened URL from the bit.ly service.
88
- #If so, you do not need to provide <i>param_type</i> (though <tt>:short_url</tt> would be the proper symbol).
89
- #
90
- #Alternately, you can provide a hash code returned by the bit.ly service.
91
- #In this case, provide <tt>:hash</tt> as the <i>param_type</i>.
92
- #
93
- #You can optionally provide an arbitrary Hash of HTTP parameters.
94
- #The one that bit.ly cares about is called <tt>:key</tt>.
95
- #It should be an array of camel-cased or underscored element names which you would like to receive.
96
- #In theory, this should limit the response content, but I haven't seen that work yet.
97
- #The arbitrary Hash capability is left intact for future re-purposing.
87
+ #For <i>url</i>, you can provide a previously-shortened URL from the bit.ly service.
88
+ #
89
+ #The URL must provide both a domain (hostname) and a Bitlink ID (path).
90
+ #A minimum-viable URL would be something along the lines of 'bit.ly/3ADCPDo'.
98
91
  #
99
92
  #A Response is returned.
100
- #Response.to_s will return the <tt>longUrl</tt> / <tt>long_url</tt> value.
93
+ #Response.to_s will return the <tt>long_url</tt> value.
101
94
  #
102
95
  #There is plenty of other data in the response besides the original full URL.
103
96
  #Feel free to access the Response.body and use Response.method_missing to pull out specific element values.
104
- def info(param, param_type=:short_url, ops={})
105
- return nil unless param_type && param
106
- assert_codes(execute(:info, :long_url) do |params|
107
- params[Utility::camelize(param_type).to_sym] = param
108
-
109
- # optional keys
110
- if (keys = ops[:keys])
111
- keys = [keys] unless Array === keys
112
- params[:keys] = (keys.inject([]) do |a, key|
113
- a << Utility::camelize(key)
114
- a
115
- end).join(',')
116
- end
117
- end)
118
- end
97
+ def info(url)
98
+ return nil unless url
99
+ uri = URI.parse(url)
100
+ bitlink = "#{uri.host}#{uri.path}"
119
101
 
120
- #Invokes the API's <b>stats</b> method.
121
- #Statistics about the shortened URL are returned by the service.
122
- #
123
- #For <i>param</i>, you can provide a previously-shortened URL from the bit.ly service.
124
- #If so, you do not need to provide <i>param_type</i> (though <tt>:short_url</tt> would be the proper symbol).
125
- #
126
- #Alternately, you can provide a hash code returned by the bit.ly service.
127
- #In this case, provide <tt>:hash</tt> as the <i>param_type</i>.
128
- #
129
- #A Response is returned.
130
- #Response.to_s will return the <tt>longUrl</tt> / <tt>long_url</tt> value.
131
- #
132
- #There is plenty of other data in the response besides the original full URL.
133
- #Feel free to access the Response.body and use Response.method_missing to pull out specific element values.
134
- def stats(param, param_type=:short_url)
135
- return nil unless param_type && param
136
- assert_codes(execute(:info, :long_url) do |params|
137
- params[Utility::camelize(param_type).to_sym] = param
138
- end)
139
- end
140
-
141
- def errors
142
- execute(:errors)
102
+ command = "bitlinks/#{bitlink}"
103
+ return execute_get(command, :long_url)
143
104
  end
144
105
 
145
106
 
@@ -147,48 +108,62 @@ module Bitly4R
147
108
  # - - - - -
148
109
  protected
149
110
 
150
- def execute(command, to_s_sym=nil) #:nodoc:
151
- #http://api.bit.ly/shorten?version=2.0.1&longUrl=http://cnn.com&login=bitlyapidemo&apiKey=R_0da49e0a9118ff35f52f629d2d71bf07
152
- uri = URI.parse('http://api.bit.ly')
111
+ def execute_get(command, to_s_sym=nil) #:nodoc:
112
+ uri = URI.parse('https://api-ssl.bitly.com')
113
+
114
+ # the client-ized set
115
+ params = Params.new
116
+
117
+ # altered in whatever way the caller desires
118
+ yield params if block_given?
119
+
120
+ response = Net::HTTP.start(uri.host, uri.port,
121
+ :use_ssl => true,
122
+ :set_debug_output => $stdout,
123
+ ) do |http|
124
+ path = "/v4/#{command}?#{params}"
125
+ request = Net::HTTP::Get.new(path)
126
+ request['Authorization'] = "Bearer #{self.token}"
127
+ request['Accept'] = 'application/json'
128
+
129
+ http.request request
130
+ end
131
+
132
+ # accept the HTTP 2XX range
133
+ raise Error.new('did not receive HTTP 200 OK') unless (/2\d{2}/ =~ response.code)
134
+
135
+ # a parsing response
136
+ Response.new(response, to_s_sym)
137
+ end
153
138
 
154
- # the client-izec set
155
- params = @client_params.clone
156
- params[:login] = self.login
157
- params[:apiKey] = self.api_key if self.api_key
139
+ def execute_post(command, to_s_sym=nil) #:nodoc:
140
+ uri = URI.parse('https://api-ssl.bitly.com')
141
+
142
+ # the client-ized set
143
+ params = Params.new
158
144
 
159
145
  # altered in whatever way the caller desires
160
146
  yield params if block_given?
161
147
 
162
- response = Net::HTTP.start(uri.host, uri.port) do |http|
163
- path = "/#{command}?#{params}"
164
- request = Net::HTTP::Get.new(path)
165
- if self.password
166
- # HTTP auth expected
167
- request.basic_auth self.login, self.password
168
- end
148
+ response = Net::HTTP.start(uri.host, uri.port,
149
+ :use_ssl => true,
150
+ # :set_debug_output => $stdout,
151
+ ) do |http|
152
+ path = "/v4/#{command}"
153
+ request = Net::HTTP::Post.new(path)
154
+ request['Authorization'] = "Bearer #{self.token}"
155
+ request['Content-Type'] = 'application/json'
156
+ request.body = params.to_json
169
157
 
170
158
  http.request request
171
159
  end
172
160
 
173
- raise Error.new('did not receive HTTP 200 OK') unless Net::HTTPOK === response
161
+ # accept the HTTP 2XX range
162
+ raise Error.new('did not receive an HTTP 2XX') unless (/2\d{2}/ =~ response.code)
174
163
 
175
164
  # a parsing response
176
165
  Response.new(response, to_s_sym)
177
166
  end
178
-
179
- def assert_error_code(response) #:nodoc:
180
- raise Error.new("errorCode #{response.errorCode} : #{response.errorMesage}") unless '0' == response.errorCode
181
- response
182
- end
183
-
184
- def assert_status_code(response) #:nodoc:
185
- raise Error.new("status #{response.statusCode}") unless 'OK' == response.statusCode
186
- response
187
- end
188
-
189
- def assert_codes(response) #:nodoc:
190
- assert_error_code(assert_status_code(response))
191
- end
192
167
  end
193
168
 
194
169
 
@@ -1,34 +1,20 @@
1
1
  #Simple constructor methods, so that you don't have to deal directly with Client if you don't want to.
2
2
  #
3
3
  #See also:
4
- #* Bitly4R.Keyed
5
- #* Bitly4R.Authed
4
+ #* Bitly4R.Token
6
5
  #
7
6
  #--
8
7
  #Many thanks to Hpricot for introducing me to this convention.
9
8
  #++
10
9
 
11
10
  #Constructs a SimpleClient with the usual Hash of arguments.
12
-
13
11
  def Bitly4R(ops={})
14
12
  # general options
15
13
  Bitly4R::SimpleClient.new(ops)
16
14
  end
17
15
 
18
- #Constructs a SimpleClient with login and API key credentials.
19
- #
20
- #No password is involved.
21
- #Simple HTTP GETs will be the order of the day.
22
- def Bitly4R.Keyed(login, api_key)
23
- # using an API key
24
- Bitly4R::SimpleClient.new(:login => login, :api_key => api_key)
25
- end
26
-
27
- #Constructs a SimpleClient with login and password credentials.
28
- #
29
- #No API key is involved.
30
- #HTTP GETs with HTTP Basic Auth will be the order of the day.
31
- def Bitly4R.Authed(login, password)
32
- # using an API key
33
- Bitly4R::SimpleClient.new(:login => login, :password => password)
16
+ #Constructs a SimpleClient with an Access Token credential
17
+ def Bitly4R.Token(token)
18
+ # just token
19
+ Bitly4R::SimpleClient.new(:token => token)
34
20
  end
@@ -68,10 +68,10 @@ module Bitly4R
68
68
  #Constructs a bit.ly API response wrapper.
69
69
  #
70
70
  #<i>response</i> can be:
71
- #* a String, which becomes the body
72
- #* a Net::HTTPResponse, in which case its body is extracted
71
+ #* a JSON String, which becomes the body
72
+ #* a Net::HTTPResponse, in which case its body is extracted and expected to be in JSON format
73
73
  #
74
- #<i>to_s_sym</i> is optional, and it references the element which will become the to_s value of this Response.
74
+ #<i>to_s_sym</i> is optional, and it references the property which will become the `#to_s` value of this Response.
75
75
  #It can be either camel-case or underscored.
76
76
  #See method_missing.
77
77
  def initialize(response, to_s_sym=nil)
@@ -80,18 +80,19 @@ module Bitly4R
80
80
  @to_s_sym = to_s_sym
81
81
  end
82
82
 
83
- #Provides access the other text elements of the response via camel-case or underscored names.
83
+ #Provides access to the other properties of the response body via camel-case or underscored names.
84
84
  #For example, <tt>longUrl</tt> and <tt>long_url</tt> are equivalent.
85
- #If no such element exists, you'll get nil.
85
+ #If no such property exists, you'll get nil.
86
86
  def method_missing(sym, *args)
87
- sym = Utility::camelize(sym.to_s)
88
- match = (self.body || '').match(%r{<#{sym}>(.*)</#{sym}>})
87
+ begin
88
+ json = JSON.parse(@body || '{}')
89
+ rescue JSON::ParserError => e
90
+ return nil
91
+ end
89
92
 
90
- unless match
91
- nil
92
- else
93
- match[1].gsub(/^<!\[CDATA\[(.*)\]\]>$/, '\1')
94
- end
93
+ # their 'v4/*' JSON convention is snake_case
94
+ sym = Utility::decamelize(sym.to_s)
95
+ return json[sym]
95
96
  end
96
97
 
97
98
  #Provides the 'likely' value from the response.
@@ -102,7 +103,9 @@ module Bitly4R
102
103
 
103
104
  #Provides the 'likely' value from the response, as a symbol.
104
105
  def to_sym
105
- @to_s_sym ? self.to_s.to_sym : super
106
+ return super unless @to_s_sym
107
+ value = self.to_s
108
+ return value.nil? ? value : value.to_sym
106
109
  end
107
110
  end
108
111
 
data/lib/bitly4r.rb CHANGED
@@ -8,7 +8,9 @@
8
8
  #--
9
9
 
10
10
  # external
11
- %w{ net/http cgi }.each {|lib| require lib }
11
+ require 'net/http'
12
+ require 'cgi'
13
+ require 'json'
12
14
 
13
15
  # internal, and in the proper sequence
14
16
  %w{
data/test/client_test.rb CHANGED
@@ -9,122 +9,83 @@ class ClientTest < Test::Unit::TestCase #:nodoc: all
9
9
  any = 'any'
10
10
 
11
11
  assert_raises Bitly4R::Error do
12
- # no login
12
+ # no token
13
13
  Bitly4R::Client.new
14
14
  end
15
15
 
16
- assert_raises Bitly4R::Error do
17
- # needs API key or password
18
- Bitly4R::Client.new(:login => any)
19
- end
20
-
21
- Bitly4R::Client.new(:login => any, :api_key => any)
22
- Bitly4R::Client.new(:login => any, :password => any)
16
+ Bitly4R::Client.new(:token => any)
23
17
  end
24
18
 
25
19
  def test_shorten
26
- # shorten
20
+ # shorten with a full Client
27
21
  client = new_client
28
22
  response = client.shorten LONG_URL
29
23
 
30
- assert_is_response_ok response
24
+ assert (Bitly4R::Response === response)
31
25
 
32
26
  # we get back what we provided
33
- assert_equal LONG_URL, response.node_key
27
+ assert_equal LONG_URL, response.long_url
34
28
 
35
29
  # no assumption as to the value, just how they inter-relate
36
- hash = response.user_hash
37
- assert hash && (! hash.empty?)
38
- short = response.short_url
39
- assert short =~ Regexp.compile(hash + '$')
30
+ id = response.id
31
+ assert id && (! id.empty?)
32
+ link = response.link
33
+ assert_equal "https://#{id}", link
34
+ assert_equal response.to_s, link
35
+
36
+ # shorten with a SimpleClient
37
+ simple_client = new_simple_client
38
+ simple_response = simple_client.shorten LONG_URL
39
+ assert (String === simple_response)
40
+ assert_equal link, simple_response
40
41
  end
41
42
 
42
43
  def test_expand
43
- # shorten ...
44
+ # shorten with a full Client
44
45
  client = new_client
45
-
46
46
  response = client.shorten(LONG_URL)
47
- assert_is_response_ok response
48
47
 
49
- hash = response.user_hash
48
+ id = response.id
50
49
  short = response.to_s
51
50
 
52
51
  # ... and re-expand
53
- # again, we don't have to know anything
52
+ # no assumption as to the value, just how they inter-relate
54
53
  response = client.expand(short)
55
- assert_is_response_ok response
56
54
 
57
55
  assert_equal LONG_URL, response.to_s
56
+ assert_equal LONG_URL, response.long_url
58
57
 
59
- # note sure what purpose it serves
60
- # but it will contain a hash-wrapped element
61
- assert ! response.__send__(hash.to_sym).empty?
62
-
63
- # ... and re-expand
64
- # again, we don't have to know anything
65
- response = client.expand(hash, :hash)
66
- assert_is_response_ok response
67
-
68
- assert_equal LONG_URL, response.to_s
69
-
70
- # again...
71
- assert ! response.__send__(hash.to_sym).empty?
58
+ # expand with a SimpleClient
59
+ simple_client = new_simple_client
60
+ simple_response = simple_client.expand short
61
+ assert (String === simple_response)
62
+ assert_equal LONG_URL, simple_response
72
63
  end
73
64
 
74
65
  def test_info
75
- # shorten ...
66
+ # shorten with a full Client
76
67
  client = new_client
77
-
78
68
  response = client.shorten(LONG_URL)
79
- assert_is_response_ok response
80
69
 
81
- hash = response.user_hash
82
70
  short = response.to_s
83
71
 
84
- # short url, with no key limit
72
+ # now, its info ...
85
73
  response = client.info(short)
86
- assert_is_response_ok response
87
-
88
- assert_equal LONG_URL, response.long_url
89
-
90
- # hash, key limit
91
- response = client.info(hash, :hash, :keys => [:long_url, :html_title])
92
- assert_is_response_ok response
93
-
94
- # well, we're getting non-included keys back
95
- # then again, the demo doesn't constrain the keys either
96
- # http://code.google.com/p/bitly-api/wiki/ApiDocumentation
97
- ###assert response.thumbnail.empty?
98
- ###assert ! response.html_title.empty?
99
- assert_equal LONG_URL, response.to_s
100
- end
101
-
102
- def test_stats
103
- # shorten ...
104
- client = new_client
105
-
106
- response = client.shorten(LONG_URL)
107
- assert_is_response_ok response
108
-
109
- hash = response.user_hash
110
- short = response.to_s
111
-
112
- { :hash => hash, :short_url => short }.each do |param_type, param|
113
- response = client.info(param, param_type)
114
- assert_is_response_ok response
115
-
116
- # we could choose anything
117
- assert_equal LONG_URL, response.to_s
118
- end
119
- end
120
-
121
- def test_errors
122
- # errors ...
123
- client = new_client
124
74
 
125
- response = client.errors
126
- assert ! response.results.empty?
127
- assert ! response.error_code.empty?
128
- assert ! response.status_code.empty?
75
+ assert_equal LONG_URL, response.to_s
76
+ assert_equal LONG_URL, response.long_url
77
+
78
+ # a few other accessable properties
79
+ # no assumption as to the value, just how they inter-relate
80
+ assert_equal "https://#{response.id}", response.link
81
+ assert_equal false, response.archived
82
+
83
+ # info with a SimpleClient
84
+ # which for this method is not "simple"; it provides a full Response
85
+ simple_client = new_simple_client
86
+ simple_response = simple_client.info short
87
+ assert (Bitly4R::Response === response)
88
+ assert_equal LONG_URL, simple_response.long_url
89
+ assert_equal false, response.archived
129
90
  end
130
91
  end
@@ -5,46 +5,28 @@ require 'test_helper'
5
5
 
6
6
 
7
7
  class DefinitionsTest < Test::Unit::TestCase #:nodoc: all
8
- def test_keyed
8
+ def test_with_token
9
9
  # shorten ...
10
- client = Bitly4R(:login => LOGIN, :api_key => API_KEY)
11
- short = client.shorten(LONG_URL)
10
+ short = Bitly4R(:token => TOKEN).shorten(LONG_URL)
12
11
  assert short && (! short.empty?)
12
+ assert (String === short)
13
13
 
14
- # ... and expand
15
- assert_equal LONG_URL, Bitly4R.Keyed(LOGIN, API_KEY).expand(short)
14
+ # ... and expand (with another Definition)
15
+ long = Bitly4R.Token(TOKEN).expand(short)
16
+ assert (String === long)
17
+ assert_equal LONG_URL, long
16
18
  end
17
19
 
18
- def test_authed
19
- unless PASSWORD
20
- puts %Q{
21
- NOTE:
22
- the text login (#{LOGIN}) did not publish a password
23
- cannot be tested without that private information
24
- }.strip
25
- return
26
- end
27
-
28
- # http://code.google.com/p/bitly-api/wiki/ApiDocumentation
29
- # sure, the documentation claims there's HTTP Auth support
30
- # but i don't see it yet
31
- short = nil
32
- assert_raises Bitly4R::Error do
33
- # shorten ...
34
- client = Bitly4R(:login => LOGIN, :password => API_KEY)
35
- short = client.shorten(LONG_URL)
36
- assert short && (! short.empty?)
37
- end
38
-
20
+ def test_without_token
39
21
  # alright, let's use the API key
40
- client = Bitly4R(:login => LOGIN, :api_key => API_KEY)
41
- short = client.shorten(LONG_URL)
42
- assert short && (! short.empty?)
22
+ client = Bitly4R(:token => 'INVALID')
23
+
24
+ assert_raises Bitly4R::Error do
25
+ client.shorten(LONG_URL)
26
+ end
43
27
 
44
- # same deal. *sigh*
45
28
  assert_raises Bitly4R::Error do
46
- # ... and expand
47
- assert_equal LONG_URL, Bitly4R.Authed(LOGIN, PASSWORD).expand(short)
29
+ Bitly4R.Token('INVALID').shorten(LONG_URL)
48
30
  end
49
31
  end
50
32
  end
data/test/objects_test.rb CHANGED
@@ -81,21 +81,20 @@ class ObjectsTest < Test::Unit::TestCase #:nodoc: all
81
81
  response = Bitly4R::Response.new('string', :bogus)
82
82
  assert_equal 'string', response.body
83
83
  assert_nil response.to_s
84
+ assert_nil response.to_sym
84
85
 
85
86
  # simple
86
- response = Bitly4R::Response.new('<a>value</a>', :b)
87
- assert_equal 'value', response.a
88
- assert_nil response.to_s
87
+ response = Bitly4R::Response.new('{"key":"value"}', :key)
88
+ assert_equal 'value', response.key
89
+ assert_nil response.another_key
90
+ assert_equal 'value', response.to_s
91
+ assert_equal :value, response.to_sym
89
92
 
90
93
  # camelization
91
- response = Bitly4R::Response.new('<uD>down</uD><dU>up</dU>', :d_u)
94
+ response = Bitly4R::Response.new('{"uD":"down","dU":"up"}', :d_u)
92
95
  assert_equal 'down', response.uD
93
96
  assert_equal 'down', response.u_d
94
97
  assert_equal 'up', response.dU
95
98
  assert_equal 'up', response.to_s
96
-
97
- # CDATA, plus to_sym
98
- response = Bitly4R::Response.new('<a><b>b</b><cData><![CDATA[data]]></cData><c>c</c></a>', :c_data)
99
- assert_equal :data, response.to_sym
100
99
  end
101
100
  end
data/test/test_helper.rb CHANGED
@@ -9,33 +9,26 @@ $LOAD_PATH.unshift File.dirname(File.dirname(__FILE__)) + "/../lib"
9
9
 
10
10
  # if we're lucky...
11
11
  begin
12
- require 'ruby-debug'
13
- rescue Object => e
12
+ require 'debug'
13
+ rescue Exception
14
14
  end
15
15
 
16
16
 
17
17
 
18
18
  class Test::Unit::TestCase #:nodoc: all
19
-
20
19
  # trailing slash makes a difference! they normalize!
21
20
  LONG_URL = 'http://rubyforge.org/'
22
21
 
23
- # credentials from
24
- # http://code.google.com/p/bitly-api/wiki/ApiDocumentation
25
- # no password provided
26
- LOGIN = 'bitlyapidemo'
27
- API_KEY = 'R_0da49e0a9118ff35f52f629d2d71bf07'
28
- PASSWORD = nil
29
-
22
+ # an Access Token credential is required
23
+ TOKEN = ENV['TOKEN']
24
+ raise Exception.new('You must provide an Access Token (TOKEN) from the environment') if (TOKEN.nil? || TOKEN.empty?)
30
25
 
31
26
 
32
- def new_client
33
- Bitly4R::Client.new(:login => LOGIN, :api_key => API_KEY)
34
- end
27
+ def new_client
28
+ Bitly4R::Client.new(:token => TOKEN)
29
+ end
35
30
 
36
- def assert_is_response_ok(response)
37
- assert_equal '0', response.error_code
38
- assert_equal '', response.error_message
39
- assert_equal 'OK', response.status_code
31
+ def new_simple_client
32
+ Bitly4R.Token(TOKEN)
40
33
  end
41
34
  end
metadata CHANGED
@@ -1,70 +1,65 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: bitly4r
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - Dan Foley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
-
12
- date: 2009-02-02 00:00:00 -08:00
13
- default_executable:
11
+ date: 2023-05-01 00:00:00.000000000 Z
14
12
  dependencies: []
15
-
16
- description: "Bitly4R : A Ruby API for the http://bit.ly URL-shortening service"
13
+ description: 'Bitly4R : A Ruby API for the http://bit.ly URL-shortening service'
17
14
  email: admin@cantremember.com
18
15
  executables: []
19
-
20
16
  extensions: []
21
-
22
- extra_rdoc_files:
17
+ extra_rdoc_files:
23
18
  - README.rdoc
24
19
  - CHANGELOG
25
20
  - LICENSE
26
- files:
21
+ files:
27
22
  - CHANGELOG
28
23
  - LICENSE
29
24
  - README.rdoc
30
25
  - Rakefile
26
+ - bitly4r.gemspec
27
+ - container
28
+ - lib/bitly4r.rb
31
29
  - lib/bitly4r/client.rb
32
30
  - lib/bitly4r/definitions.rb
33
31
  - lib/bitly4r/objects.rb
34
- - lib/bitly4r.rb
35
- has_rdoc: true
32
+ - test/client_test.rb
33
+ - test/definitions_test.rb
34
+ - test/objects_test.rb
35
+ - test/test_helper.rb
36
36
  homepage: http://wiki.cantremember.com/Bitly4R
37
+ licenses:
38
+ - WTFPL
39
+ metadata: {}
37
40
  post_install_message:
38
- rdoc_options:
39
- - --line-numbers
40
- - --inline-source
41
- - --title
41
+ rdoc_options:
42
+ - "--line-numbers"
43
+ - "--inline-source"
44
+ - "--title"
42
45
  - Bitly4R
43
- - --main
46
+ - "--main"
44
47
  - README.rdoc
45
- require_paths:
48
+ require_paths:
46
49
  - lib
47
- required_ruby_version: !ruby/object:Gem::Requirement
48
- requirements:
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
49
52
  - - ">="
50
- - !ruby/object:Gem::Version
51
- version: "1.8"
52
- version:
53
- required_rubygems_version: !ruby/object:Gem::Requirement
54
- requirements:
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
55
57
  - - ">="
56
- - !ruby/object:Gem::Version
57
- version: "0"
58
- version:
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
59
60
  requirements: []
60
-
61
- rubyforge_project: bitly4r
62
- rubygems_version: 1.3.1
61
+ rubygems_version: 3.3.26
63
62
  signing_key:
64
- specification_version: 2
65
- summary: bitly4r 0.1.0
66
- test_files:
67
- - test/client_test.rb
68
- - test/definitions_test.rb
69
- - test/objects_test.rb
70
- - test/test_helper.rb
63
+ specification_version: 4
64
+ summary: bitly4r 0.2.0
65
+ test_files: []