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 +2 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +60 -0
- data/RakeFile +48 -0
- data/VERSION +1 -0
- data/lib/intercepts/net_http.rb +36 -0
- data/lib/middleman.rb +41 -0
- data/lib/store/file.rb +42 -0
- data/middleman.gemspec +48 -0
- data/spec/middleman_spec.rb +126 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +36 -0
- metadata +65 -0
data/.gitignore
ADDED
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
data/spec/spec_helper.rb
ADDED
@@ -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
|