rlivsey-middleman 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ cache
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Richard Livsey
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.markdown ADDED
@@ -0,0 +1,60 @@
1
+ ## About
2
+
3
+ Middleman is a simple logging/caching proxy for Net::HTTP which can make developing against remote services easier (especially if they have API limits).
4
+
5
+ By default, it caches to a file, so the cache is persistent across multiple runs of your app.
6
+
7
+ ## Installation
8
+
9
+ gem sources -a http://gems.github.com
10
+ sudo gem install rlivsey-middleman
11
+
12
+ ## Example usage
13
+
14
+ require 'rubygems'
15
+ require 'twitter'
16
+ gem 'middleman'
17
+ require 'middleman'
18
+
19
+ Twitter::Search.new('bacon') # makes the request to Twitter
20
+ Twitter::Search.new('bacon') # same search, so returns from the cache
21
+
22
+ ## Options
23
+
24
+ Output information to the console
25
+
26
+ Middleman.options[:verbose] = true
27
+
28
+ Change the store used for the cache, see the 'stores' section below for more information,
29
+ but it's basically an object which acts like a Hash
30
+
31
+ Middleman.options[:store] = {}
32
+
33
+ Change where verbose output is sent, by default it's STDOUT
34
+
35
+ Middleman.options[:logger] = Logger.new('middleman.log')
36
+
37
+
38
+ ## Stores
39
+
40
+ By default Middleman uses Middleman::Store::File to cache the requests to files in a directory.
41
+ The file names are MD5 hashes of the request details.
42
+
43
+ The interface to Middleman::Store::File is basically a Hash, so any object which responds to [], []= and
44
+ is enumerable can be used as a store.
45
+
46
+ Using a Hash for the store will work fine, but will not persist across runs of your application.
47
+
48
+ ## Notes
49
+
50
+ At the moment this only works against Net::HTTP. I've got plans to make it easier to extend and add the ability to work with other libraries such as Curb etc...
51
+
52
+ Feel free to fork and send in patches.
53
+
54
+ ## Me
55
+
56
+ * Home & Contact info: http://livsey.org
57
+ * Twitter: http://twitter.com/rlivsey
58
+ * GitHub: http://github.com/rlivsey
59
+ * Recommend: http://www.workingwithrails.com/person/5436-richard-livsey
60
+
data/RakeFile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "middleman"
8
+ gem.summary = "simple logging/caching proxy for Net::HTTP"
9
+ gem.email = "richard@livsey.org"
10
+ gem.homepage = "http://github.com/rlivsey/middleman"
11
+ gem.authors = ["Richard Livsey"]
12
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
13
+ end
14
+
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
+ end
18
+
19
+ require 'spec/rake/spectask'
20
+ Spec::Rake::SpecTask.new(:spec) do |spec|
21
+ spec.libs << 'lib' << 'spec'
22
+ spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+
32
+ task :default => :spec
33
+
34
+ require 'rake/rdoctask'
35
+ Rake::RDocTask.new do |rdoc|
36
+ if File.exist?('VERSION.yml')
37
+ config = YAML.load(File.read('VERSION.yml'))
38
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
39
+ else
40
+ version = ""
41
+ end
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "Middleman #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,36 @@
1
+ module Net
2
+ class HTTP
3
+ alias :old_initialize :initialize
4
+ alias :old_request :request
5
+
6
+ def initialize(*args, &block)
7
+ Middleman.log "CONNECT: #{args.inspect}" if Middleman.options[:verbose]
8
+ old_initialize(*args, &block)
9
+ end
10
+
11
+ def request(*args, &block)
12
+ req = args[0].class::METHOD
13
+ key = "#{req}:#{@address}:#{@port}#{args[0].path}"
14
+
15
+ if started? && Middleman.options[:verbose]
16
+ Middleman.log "#{req} #{@address}:#{@port}#{args[0].path}"
17
+ end
18
+
19
+ if result = Middleman.retrieve(key)
20
+ Middleman.log "CACHE HIT"
21
+ else
22
+ Middleman.log "NOT IN CACHE"
23
+ result = old_request(*args, &block)
24
+ Middleman.cache(key, result.body)
25
+ end
26
+
27
+ if started? && Middleman.options[:verbose]
28
+ Middleman.log "PARAMS #{CGI.parse(args[0].body).inspect} " if args[0].body && req != 'CONNECT'
29
+ Middleman.log "RESPONSE: #{result.class.name}"
30
+ end
31
+
32
+ result
33
+ end
34
+
35
+ end
36
+ end
data/lib/middleman.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'store/file'
2
+ require 'intercepts/net_http'
3
+
4
+ module Middleman
5
+
6
+ # default options
7
+ @options = {
8
+ :verbose => false, # don't output any info
9
+ :logger => nil, # defaults to STDOUT
10
+ :store => {}
11
+ }
12
+
13
+ class << self
14
+ attr_accessor :options
15
+
16
+ def store
17
+ @options[:store]
18
+ end
19
+
20
+ def logger
21
+ @options[:logger]
22
+ end
23
+
24
+ def log(message)
25
+ return unless @options[:verbose]
26
+ logger ? logger.info(message) : puts(message)
27
+ end
28
+
29
+ def cache(key, value)
30
+ return unless store
31
+ store[key] = value
32
+ end
33
+
34
+ def retrieve(key)
35
+ return unless store
36
+ store[key]
37
+ end
38
+
39
+ end
40
+
41
+ end
data/lib/store/file.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'fileutils'
2
+ require 'digest/md5'
3
+
4
+ module Middleman
5
+ module Store
6
+ class File
7
+
8
+ attr_accessor :path
9
+
10
+ def initialize(path)
11
+ @path = path.chomp('/')
12
+
13
+ unless ::File.exists? path
14
+ FileUtils.mkdir_p(path)
15
+ end
16
+
17
+ end
18
+
19
+ def [](key)
20
+ return unless ::File.exist?(path_from_key(key))
21
+ Marshal.load(::File.read(path_from_key(key)))
22
+ end
23
+
24
+ def []=(key, val)
25
+ ::File.open(path_from_key(key), 'w') do |f|
26
+ f.write(Marshal.dump(val))
27
+ end
28
+ end
29
+
30
+ def clear
31
+ ::File.delete(*Dir["#{@path}/*"])
32
+ end
33
+
34
+ private
35
+
36
+ def path_from_key(key)
37
+ "#{@path}/#{Digest::MD5.hexdigest(key)}"
38
+ end
39
+
40
+ end
41
+ end
42
+ end
data/middleman.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{middleman}
5
+ s.version = "0.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Richard Livsey"]
9
+ s.date = %q{2009-05-08}
10
+ s.email = %q{richard@livsey.org}
11
+ s.extra_rdoc_files = [
12
+ "README.markdown"
13
+ ]
14
+ s.files = [
15
+ ".gitignore",
16
+ "MIT-LICENSE",
17
+ "README.markdown",
18
+ "RakeFile",
19
+ "VERSION",
20
+ "lib/intercepts/net_http.rb",
21
+ "lib/middleman.rb",
22
+ "lib/store/file.rb",
23
+ "middleman.gemspec",
24
+ "spec/middleman_spec.rb",
25
+ "spec/spec.opts",
26
+ "spec/spec_helper.rb"
27
+ ]
28
+ s.has_rdoc = true
29
+ s.homepage = %q{http://github.com/rlivsey/middleman}
30
+ s.rdoc_options = ["--charset=UTF-8"]
31
+ s.require_paths = ["lib"]
32
+ s.rubygems_version = %q{1.3.1}
33
+ s.summary = %q{simple logging/caching proxy for Net::HTTP}
34
+ s.test_files = [
35
+ "spec/middleman_spec.rb",
36
+ "spec/spec_helper.rb"
37
+ ]
38
+
39
+ if s.respond_to? :specification_version then
40
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
41
+ s.specification_version = 2
42
+
43
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
44
+ else
45
+ end
46
+ else
47
+ end
48
+ end
@@ -0,0 +1,126 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'pp'
3
+
4
+ describe Middleman do
5
+
6
+ def do_get
7
+ Net::HTTP.get(URI.parse('http://www.google.com?q=test'))
8
+ end
9
+
10
+ describe "default options" do
11
+
12
+ it "should not be verbose" do
13
+ Middleman.options[:verbose].should == false
14
+ end
15
+
16
+ it "should be a hash store" do
17
+ Middleman.options[:store].class.should == Hash
18
+ end
19
+
20
+ it "should not have a logger" do
21
+ Middleman.options[:logger].should be_nil
22
+ end
23
+
24
+ end
25
+
26
+ describe "with store" do
27
+
28
+ before :each do
29
+ @store = mock(:store, :null_object => true)
30
+ @store.clear
31
+ Middleman.options[:store] = @store
32
+ end
33
+
34
+ it "should store the result of the request in a file the first time" do
35
+ Middleman.store.should_receive(:[]).and_return(nil)
36
+ Middleman.store.should_receive(:[]=).once
37
+ do_get
38
+ end
39
+
40
+ it "should retrieve the results from the cache on subsequent requests" do
41
+ Middleman.store.should_receive(:[]).and_return(mock(:response, :null_object => true))
42
+ Middleman.store.should_not_receive(:[]=)
43
+ do_get
44
+ end
45
+
46
+ end
47
+
48
+ describe "with no store" do
49
+ before :all do
50
+ Middleman.options[:store] = nil
51
+ end
52
+
53
+ it "should not die..." do
54
+ do_get
55
+ end
56
+
57
+ end
58
+
59
+ describe "with verbose logging" do
60
+
61
+ before :all do
62
+ Middleman.options[:verbose] = true
63
+ Middleman.options[:logger] = DummyLogger.new
64
+ end
65
+
66
+ it "should log to the logger" do
67
+ Middleman.options[:logger].lines.should be_empty
68
+ do_get
69
+ Middleman.options[:logger].lines.should_not be_empty
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+
76
+
77
+
78
+
79
+ describe Middleman::Store::File do
80
+
81
+ before :each do
82
+ @store = Middleman::Store::File.new('cache/mman')
83
+ @store.clear
84
+ end
85
+
86
+ it "should create the cache dir if it doesn't exist" do
87
+ FileUtils.rm_rf('cache')
88
+ File.exist?('cache').should == false
89
+ Middleman::Store::File.new('cache/mman')
90
+ File.exist?('cache').should == true
91
+ end
92
+
93
+ describe "#clear" do
94
+
95
+ it "should delete all the files in the cache directory" do
96
+ @store["test"] = 'test'
97
+ Dir["#{@store.path}/*"].should_not be_empty
98
+ @store.clear
99
+ Dir["#{@store.path}/*"].should be_empty
100
+ end
101
+
102
+ end
103
+
104
+ describe "#[]" do
105
+
106
+ it "should retrieve the contents of the file if it exists" do
107
+ @store["test"] = 'test'
108
+ @store["test"].should == 'test'
109
+ end
110
+
111
+ it "should return nil if the file doesn't exist" do
112
+ @store["test"].should == nil
113
+ end
114
+
115
+ end
116
+
117
+ describe "#[]=" do
118
+
119
+ it "should create a file with the MD5 of the name" do
120
+ @store["test"] = 'test'
121
+ File.exist?("#{@store.path}/#{Digest::MD5.hexdigest('test')}").should == true
122
+ end
123
+
124
+ end
125
+
126
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --format
2
+ progress
3
+ --colour
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
7
+ require 'net/http'
8
+ require 'twitter'
9
+ require 'middleman'
10
+
11
+ Spec::Runner.configure do |config|
12
+
13
+ end
14
+
15
+ # used so we don't pollute STDOUT when running the specs
16
+ class DummyLogger
17
+
18
+ attr_accessor :lines
19
+
20
+ def initialize
21
+ reset!
22
+ end
23
+
24
+ def <<(msg)
25
+ @lines << msg
26
+ end
27
+
28
+ def info(msg)
29
+ @lines << msg
30
+ end
31
+
32
+ def reset!
33
+ @lines = []
34
+ end
35
+
36
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlivsey-middleman
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Livsey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-08 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: richard@livsey.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - .gitignore
26
+ - MIT-LICENSE
27
+ - README.markdown
28
+ - RakeFile
29
+ - VERSION
30
+ - lib/intercepts/net_http.rb
31
+ - lib/middleman.rb
32
+ - lib/store/file.rb
33
+ - middleman.gemspec
34
+ - spec/middleman_spec.rb
35
+ - spec/spec.opts
36
+ - spec/spec_helper.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/rlivsey/middleman
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --charset=UTF-8
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.2.0
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: simple logging/caching proxy for Net::HTTP
63
+ test_files:
64
+ - spec/middleman_spec.rb
65
+ - spec/spec_helper.rb