rlivsey-middleman 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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