flareshow 0.3.1

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.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Flareshow.gemspec ADDED
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{flareshow}
8
+ s.version = "0.3.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Will Bailey"]
12
+ s.date = %q{2010-01-11}
13
+ s.description = %q{a ruby gem for interacting with the shareflow collaboration service by Zenbe}
14
+ s.email = %q{will.bailey@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "Flareshow.gemspec",
22
+ "LICENSE",
23
+ "README.md",
24
+ "Rakefile",
25
+ "TODO",
26
+ "VERSION",
27
+ "lib/cache.rb",
28
+ "lib/comment.rb",
29
+ "lib/exceptions.rb",
30
+ "lib/file_attachment.rb",
31
+ "lib/flareshow.rb",
32
+ "lib/flow.rb",
33
+ "lib/http_encoding_helper.rb",
34
+ "lib/invitation.rb",
35
+ "lib/membership.rb",
36
+ "lib/mime_parts.rb",
37
+ "lib/post.rb",
38
+ "lib/resource.rb",
39
+ "lib/searchable.rb",
40
+ "lib/server.rb",
41
+ "lib/service.rb",
42
+ "lib/user.rb",
43
+ "lib/util.rb",
44
+ "test/flareshow_test.rb",
45
+ "test/test_helper.rb"
46
+ ]
47
+ s.homepage = %q{http://github.com/willbailey/flareshow}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubyforge_project = %q{flareshow}
51
+ s.rubygems_version = %q{1.3.5}
52
+ s.summary = %q{a ruby gem for interacting with the shareflow collaboration service}
53
+ s.test_files = [
54
+ "test/flareshow_test.rb",
55
+ "test/test_helper.rb"
56
+ ]
57
+
58
+ if s.respond_to? :specification_version then
59
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
60
+ s.specification_version = 3
61
+
62
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
63
+ s.add_development_dependency(%q<thoughtbot-shoulda>, ["> 0"])
64
+ s.add_runtime_dependency(%q<json>, ["> 0"])
65
+ s.add_runtime_dependency(%q<curb>, ["> 0"])
66
+ s.add_runtime_dependency(%q<facets>, ["> 0"])
67
+ s.add_runtime_dependency(%q<uuid>, ["> 0"])
68
+ else
69
+ s.add_dependency(%q<thoughtbot-shoulda>, ["> 0"])
70
+ s.add_dependency(%q<json>, ["> 0"])
71
+ s.add_dependency(%q<curb>, ["> 0"])
72
+ s.add_dependency(%q<facets>, ["> 0"])
73
+ s.add_dependency(%q<uuid>, ["> 0"])
74
+ end
75
+ else
76
+ s.add_dependency(%q<thoughtbot-shoulda>, ["> 0"])
77
+ s.add_dependency(%q<json>, ["> 0"])
78
+ s.add_dependency(%q<curb>, ["> 0"])
79
+ s.add_dependency(%q<facets>, ["> 0"])
80
+ s.add_dependency(%q<uuid>, ["> 0"])
81
+ end
82
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Will Bailey
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,122 @@
1
+ ___ ___ __
2
+ /'___\\_ \ /\ \
3
+ /\ \__///\ \ __ _ __ __ ____\ \ \___ ___ __ __ __
4
+ \ \ ,__\\ \ \ /'__`\ /\`'__\'__`\ /',__\\ \ _ `\ / __`\/\ \/\ \/\ \
5
+ \ \ \_/ \_\ \_/\ \L\.\_\ \ \/\ __//\__, `\\ \ \ \ \/\ \L\ \ \ \_/ \_/ \
6
+ \ \_\ /\____\ \__/.\_\\ \_\ \____\/\____/ \ \_\ \_\ \____/\ \___x___/'
7
+ \/_/ \/____/\/__/\/_/ \/_/\/____/\/___/ \/_/\/_/\/___/ \/__//__/
8
+
9
+ ~ a ruby wrapper for the Zenbe Shareflow API
10
+
11
+
12
+ ### Overview
13
+
14
+ Flareshow provides a ruby wrapper around the shareflow json rpc wire protocol.
15
+
16
+ For more information about the Shareflow API see:
17
+ <http://docs.google.com/View?id=dchr4h9d_5gz6nw3cb>
18
+
19
+ ### Getting Started
20
+ You'll need a shareflow account setup before you can begin interacting with the api. Go to <http://getshareflow.com> and sign up for a free account.
21
+
22
+ ### Authentication
23
+
24
+ All actions in Flareshow require authenticationFlareshow can automatically authenticate you against your shareflow server. Just create a YAML formatted .flareshowrc file in your home directory with the following keys
25
+
26
+ subdomain : demo.zenbe.com
27
+ login : demo
28
+ password : password
29
+
30
+ To authenticate manually do the following:
31
+
32
+ Flareshow::Service.configure(<subdomain>)
33
+ Flareshow.authenticate(<login>, <password>)
34
+
35
+ ### Usage
36
+
37
+ Once you've authenticated you can choose to use either interact directly with the Flareshow::Service or use the Flareshow::Resource domain models which encapsulate the domain logic of Shareflow providing a friendlier development environment.
38
+
39
+ ### Examples
40
+
41
+ #### accessing models and associations
42
+
43
+ Flareshow offers an ActiveRecord like syntax for retrieving and manipulating models.
44
+
45
+ # Get the first post from the server ordered by creation date by default
46
+ p = Post.first
47
+
48
+ # Get the comments for that post
49
+ p.comments
50
+
51
+ # get the file attachments for the post
52
+ files = p.files
53
+
54
+ # download a file
55
+ files.first.download
56
+
57
+
58
+ #### reading posts
59
+
60
+ # the following code will read all posts on the server in a loop
61
+ per_request = 30
62
+ results = []
63
+ offset = 0
64
+
65
+ loop do
66
+ posts = Post.find(:offset => offset, :limit => per_request)
67
+ results += posts
68
+ puts results.size
69
+ offset += per_request
70
+ break if posts.empty?
71
+ end
72
+
73
+ #### upload a file to a Post
74
+
75
+ p=Post.new()
76
+ p.save
77
+ p.create_file("/path/to/your/file")
78
+
79
+ #### searching for a post
80
+
81
+ # posts, files, comments include the searchable mixin
82
+ # and can be searched using full text search capabilities
83
+ # on the server
84
+ results = Post.search("some keywords")
85
+
86
+ #### deleting a post or comment
87
+
88
+ Post.first.destroy
89
+ Comment.first.destroy
90
+
91
+ #### renaming a flow
92
+
93
+ f=Flow.find_by_name('test')
94
+ f.name = 'a different name'
95
+ f.save
96
+
97
+ #### inviting someone to a flow (only available if you are the creator of the flow)
98
+
99
+ f=Flow.find_by_name('test')
100
+ f.send_invitations('test@test.com')
101
+
102
+ # this also works
103
+ f.send_invitations(['test1@test.com', 'test2@test.com'])
104
+
105
+ #### canceling an invitation to a flow (only available if you are the creator of the flow)
106
+
107
+ f=Flow.find_by_name('test')
108
+ # revoke an invitation by the email address that was invited
109
+ f.revoke_invitations('test@test.com')
110
+
111
+
112
+ #### removing a user from a flow (only available if you are the creator of the flow)
113
+
114
+ f = Flow.find_by_name('test')
115
+ users = f.list_users # get a listing of the users on the flow
116
+ # remove the last user in the list from the flow...you cant remove yourself in this way
117
+ f.remove_members(users.last.id)
118
+
119
+ #### listing all the users on a flow
120
+
121
+ f=Flow.first
122
+ f.list_users
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "flareshow"
8
+ gem.summary = %Q{a ruby gem for interacting with the shareflow collaboration service}
9
+ gem.description = %Q{a ruby gem for interacting with the shareflow collaboration service by Zenbe}
10
+ gem.email = "will.bailey@gmail.com"
11
+ gem.homepage = "http://github.com/willbailey/flareshow"
12
+ gem.authors = ["Will Bailey"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", "> 0"
14
+ gem.add_dependency "json", "> 0"
15
+ gem.add_dependency "curb", "> 0"
16
+ gem.add_dependency "facets", "> 0"
17
+ gem.add_dependency "uuid", "> 0"
18
+ gem.rubyforge_project = "flareshow"
19
+ end
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:test) do |test|
26
+ test.libs << 'lib' << 'test'
27
+ test.pattern = 'test/**/*_test.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/*_test.rb'
36
+ test.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+ task :test => :check_dependencies
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/rdoctask'
49
+ Rake::RDocTask.new do |rdoc|
50
+ if File.exist?('VERSION')
51
+ version = File.read('VERSION')
52
+ else
53
+ version = ""
54
+ end
55
+
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "flareshow #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
data/TODO ADDED
@@ -0,0 +1,14 @@
1
+ TODO:
2
+ shareflow api docs
3
+ write tests with Fakeweb
4
+ flesh out more resource methods
5
+ make post requests with embedded file attachments respond with the file attachments for now...later we need to allow the creation of files in the same way as posts as flat
6
+ namespaced objects
7
+ handle failure states on requests
8
+ namespace auth requests to be consistent with other api calls
9
+
10
+ TODONE:
11
+ remove temporary auth setup logging in user automatically
12
+
13
+ QUESTIONS:
14
+ should authentication responses look like query and commit responses namespacing is applied differently in authentication currently?
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.1
data/lib/cache.rb ADDED
@@ -0,0 +1,91 @@
1
+ # provides an interface for various
2
+ # caches that flareshow might use
3
+ class Flareshow::CacheManager
4
+
5
+ class << self
6
+ # assimilate the resources provided in the response
7
+ def assimilate_resources(data)
8
+ # process each resource key and generate a new object
9
+ # or merge the object data with an existing object
10
+ data.inject({}) do |memo,resource_pair|
11
+ resource_key, resources = resource_pair[0], resource_pair[1]
12
+
13
+ fs_resource_array = memo[resource_key] ||= []
14
+ klass_name = Flareshow::ResourceToClassMap[resource_key]
15
+ klass = Kernel.const_get(klass_name)
16
+ if klass_name
17
+ if klass
18
+ resources.each do |resource_data|
19
+ item = cache.get_resource(resource_key, resource_data["id"])
20
+ if item
21
+ item.update(resource_data, :server)
22
+ else
23
+ item = klass.new(resource_data, :server)
24
+ end
25
+ cache.set_resource(resource_key, item.id, item)
26
+ fs_resource_array << item
27
+ end
28
+ end
29
+ end
30
+ memo
31
+ end
32
+ end
33
+
34
+ # get the managed cache object
35
+ def cache
36
+ @cache ||= Flareshow::Cache.new
37
+ end
38
+
39
+ end
40
+
41
+
42
+ end
43
+
44
+ # a simple in memory cache for Flareshow objects
45
+ class Flareshow::Cache
46
+
47
+ # you can create your own cache object and plug it into the cache manager.
48
+ # The cache class should implement the public methods
49
+ # get_resource, set_resource, delete_resource, list_resource, flush and size
50
+
51
+ # load a resource from the cache
52
+ def get_resource(resource_key, id)
53
+ resource_cache(resource_key)[id]
54
+ end
55
+
56
+ # set a resource in the cache
57
+ def set_resource(resource_key, id, object)
58
+ resource_cache(resource_key)[id] = object
59
+ end
60
+
61
+ # remove a resource
62
+ def delete_resource(resource_key, id)
63
+ resource_cache(resource_key).delete(id)
64
+ end
65
+
66
+ def list_resource(resource_key)
67
+ resource_cache(resource_key)
68
+ end
69
+
70
+ # remove all cached objects
71
+ def flush
72
+ data = {}
73
+ end
74
+
75
+ # number of cached objects
76
+ def size
77
+ data.values.inject(0){|m,v| m+=v.size}
78
+ end
79
+
80
+ private
81
+ # data store for the cache
82
+ def data
83
+ @cache ||= {}
84
+ end
85
+
86
+ # get a specific resource dictionary
87
+ def resource_cache(resource_key)
88
+ data[resource_key] ||= Dictionary.new
89
+ end
90
+
91
+ end
data/lib/comment.rb ADDED
@@ -0,0 +1,28 @@
1
+ class Comment < Flareshow::Resource
2
+
3
+ @attr_accessible = [:content, :post_id]
4
+ @attr_required = [:post_id, :content]
5
+
6
+ extend Flareshow::Searchable
7
+
8
+ # permalink to this comment
9
+ def permalink(mobile=false)
10
+ if mobile
11
+ "http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/mobile/post/#{reply_to}"
12
+ else
13
+ "http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/p/#{reply_to}?comment_id#{id}"
14
+ end
15
+ end
16
+
17
+ # get the post for this comment
18
+ def post
19
+ Post.first(:id => post_id)
20
+ end
21
+
22
+ # user for this post
23
+ def user
24
+ return User.current unless user_id
25
+ User.first({:id => user_id})
26
+ end
27
+
28
+ end
data/lib/exceptions.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Flareshow
2
+
3
+ class MissingRequiredField < Exception
4
+ def message
5
+ "you attempted to save an object without providing all of the required fields"
6
+ end
7
+ end
8
+
9
+ class APIAccessException < Exception
10
+ def message
11
+ "you've attempted to change an object in a way not permitted by the API"
12
+ end
13
+ end
14
+
15
+ class ConfigurationException < Exception
16
+ def message
17
+ "the shareflow service connection has not been configured properly"
18
+ end
19
+ end
20
+
21
+ class AuthenticationRequired < Exception
22
+ def message
23
+ "this action requires authentication"
24
+ end
25
+ end
26
+
27
+ class AuthenticationFailed < Exception
28
+ def message
29
+ "authentication failed"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ class FileAttachment < Flareshow::Resource
2
+
3
+ @read_only=true
4
+
5
+ extend Flareshow::Searchable
6
+
7
+ # =================
8
+ # = Class Methods =
9
+ # =================
10
+ class << self
11
+ # file attachments has a resource key of files
12
+ # for querying the server
13
+ def resource_key
14
+ "files"
15
+ end
16
+ end
17
+
18
+ # download the file contents
19
+ def download
20
+ url = self.url
21
+ unless url.match(/http/)
22
+ url = "http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}#{url}"
23
+ end
24
+ Flareshow::Util.log_info("getting #{url}")
25
+ Flareshow::Service.http_get(url)
26
+ end
27
+
28
+ # post for this file
29
+ def post
30
+ return false unless post_id
31
+ Post.find({:id => post_id})
32
+ end
33
+
34
+ # get the user for this file
35
+ def user
36
+ p = post && post.first
37
+ p.user && p.user.first
38
+ end
39
+
40
+ end
data/lib/flareshow.rb ADDED
@@ -0,0 +1,61 @@
1
+ ROOT = File.dirname(__FILE__) unless defined? ROOT
2
+
3
+ # gems
4
+ require 'rubygems' #TODO fix
5
+ require 'json'
6
+ require 'facets'
7
+ require 'facets/dictionary'
8
+ require 'uuid'
9
+ require 'mime/types'
10
+ require 'cgi'
11
+
12
+ # std lib
13
+ require 'net/http'
14
+ require 'net/https'
15
+ require 'ostruct'
16
+ require 'yaml'
17
+ require 'logger'
18
+ require 'ruby-debug'
19
+
20
+ # Application Constants and configuration
21
+ module Flareshow
22
+
23
+ # mappings to allow easy conversion from the
24
+ # response keys the server sends back in JSUP
25
+ # messages
26
+ ResourceToClassMap = {
27
+ "flows" => "Flow",
28
+ "posts" => "Post",
29
+ "comments" => "Comment",
30
+ "files" => "FileAttachment",
31
+ "memberships" => "Membership",
32
+ "invitations" => "Invitation",
33
+ "users" => "User"
34
+ } unless defined? ResourceToClassMap
35
+ ClassToResourceMap = ResourceToClassMap.invert unless defined? ClassToResourceMap
36
+ end
37
+
38
+ # app
39
+ require File.join(ROOT, 'service')
40
+ require File.join(ROOT, 'resource')
41
+ require File.join(ROOT, 'cache')
42
+ require File.join(ROOT, 'searchable')
43
+
44
+ # logging
45
+ DEFAULT_LOGGER = Logger.new(STDOUT) unless defined?(DEFAULT_LOGGER)
46
+ DEFAULT_LOGGER.level = Logger::ERROR
47
+ Dir.glob(File.join(ROOT, "*.rb")).each{|lib| require lib}
48
+
49
+ # check for presence of config file
50
+ config_file_path = File.expand_path("~/.flareshowrc")
51
+ if File.exists?(config_file_path) && !Flareshow::Service.authenticated?
52
+ data = YAML.load_file(config_file_path)
53
+ Flareshow::Service.debug_output=true if data["debug_http"]
54
+ host = data["host"] || "biz.zenbe.com"
55
+ subdomain = data["subdomain"]
56
+ DEFAULT_LOGGER.level = data["log_level"].to_i if data["log_level"]
57
+ Flareshow::Service.configure(subdomain, host)
58
+ if data["login"] && data["password"]
59
+ User.log_in(data["login"], data["password"])
60
+ end
61
+ end
data/lib/flow.rb ADDED
@@ -0,0 +1,78 @@
1
+ class Flow < Flareshow::Resource
2
+
3
+ @attr_accessible = [:name, :remove_members, :uninvite, :invite]
4
+ @attr_required = [:name]
5
+
6
+ # =================
7
+ # = Class Methods =
8
+ # =================
9
+ class << self
10
+ # find a flow by name
11
+ def find_by_name(name)
12
+ self.first({:name => name})
13
+ end
14
+ end
15
+
16
+ # permalink for this flow
17
+ def permalink(mobile=false)
18
+ if mobile
19
+ "http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/mobile/flows/#{id}"
20
+ else
21
+ "http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/c/#{id}"
22
+ end
23
+ end
24
+
25
+ #invite/reinvite a user to a flow by email address
26
+ def send_invitations(email_addresses)
27
+ self.invite = [email_addresses].flatten
28
+ self.save
29
+ end
30
+
31
+ # uninvite an invited user from a flow by email address
32
+ def revoke_invitations(email_addresses)
33
+ self.uninvite = [email_addresses].flatten
34
+ self.save
35
+ end
36
+
37
+ # remove a user from a flow
38
+ # you must be the owner of the flow to perform
39
+ # this action
40
+ def remove_members(member_ids)
41
+ self.remove_members = [member_ids].flatten
42
+ self.save
43
+ end
44
+
45
+ # build a new post but don't persist it immediatel
46
+ def build_post(attributes)
47
+ post = Post.new
48
+ post.update(attributes)
49
+ post.flow_id = id
50
+ post
51
+ end
52
+
53
+ # create a new post in this flow
54
+ def create_post(attributes)
55
+ p=build_post(attributes)
56
+ p.save
57
+ end
58
+
59
+ # posts for this flow...only returns the first 100 (API max)
60
+ # to load all posts you can interact with the Service class directly
61
+ # to loop through in batches of 100 using the offset parameter or
62
+ # create a flow object and override this method with the looping logic
63
+ def posts
64
+ Post.find(:flow_id => id)
65
+ end
66
+
67
+ # list the invitations to this flow
68
+ def list_invitations
69
+ Invitation.find(:flow_id => id)
70
+ end
71
+
72
+ # list all users on the flow currently
73
+ def list_users
74
+ response = Flareshow::Service.query({:flows=>{:id => self.id, :limit => 1, :include=>['users']}})
75
+ (Flareshow::CacheManager.assimilate_resources(response["resources"]) || {})["users"]
76
+ end
77
+
78
+ end
@@ -0,0 +1,49 @@
1
+ # Intended to extend the Net::HTTP response object
2
+ # and adds support for decoding gzip and deflate encoded pages
3
+ #
4
+ # Author: Jason Stirk <http://griffin.oobleyboo.com>
5
+ # Home: http://griffin.oobleyboo.com/projects/http_encoding_helper
6
+ # Created: 5 September 2007
7
+ # Last Updated: 23 November 2007
8
+ #
9
+ # Usage:
10
+ #
11
+ # require 'net/http'
12
+ # require 'http_encoding_helper'
13
+ # headers={'Accept-Encoding' => 'gzip, deflate' }
14
+ # http = Net::HTTP.new('griffin.oobleyboo.com', 80)
15
+ # http.start do |h|
16
+ # request = Net::HTTP::Get.new('/', headers)
17
+ # response = http.request(request)
18
+ # content=response.plain_body # Method from our library
19
+ # puts "Transferred: #{response.body.length} bytes"
20
+ # puts "Compression: #{response['content-encoding']}"
21
+ # puts "Extracted: #{response.plain_body.length} bytes"
22
+ # end
23
+ #
24
+
25
+ require 'zlib'
26
+ require 'stringio'
27
+
28
+ class Net::HTTPResponse
29
+ # Return the uncompressed content
30
+ def plain_body
31
+ encoding=self['content-encoding']
32
+ content=nil
33
+ if encoding then
34
+ case encoding
35
+ when 'gzip'
36
+ i=Zlib::GzipReader.new(StringIO.new(self.body))
37
+ content=i.read
38
+ when 'deflate'
39
+ i=Zlib::Inflate.new
40
+ content=i.inflate(self.body)
41
+ else
42
+ raise "Unknown encoding - #{encoding}"
43
+ end
44
+ else
45
+ content=self.body
46
+ end
47
+ return content
48
+ end
49
+ end