bitly4r 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []